From dfb5ab475e4388c839a9226e854fc61c53a94e01 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 8 Oct 2021 15:55:41 +0200 Subject: [PATCH 001/117] Optimize addTargets() method Don't lookup for matching targetDetails on every iteration. Before we start a loop we prepare the appropriate hash and use it on every iteration instead. This shortens the total time spent on findOrDefault from about 2 seconds to about 10 miliseconds now. Change-Id: I89bb3f472bc9071a54f9900fa057f87b57d4742d Reviewed-by: Cristian Adam Reviewed-by: Qt CI Bot --- .../cmakeprojectmanager/fileapidataextractor.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index cabac0b3b98..c4f4810f34f 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -595,9 +595,20 @@ void addTargets(const QHash &cm const FilePath &sourceDir, const FilePath &buildDir) { + QHash targetDetailsHash; + for (const TargetDetails &t : targetDetails) + targetDetailsHash.insert(t.id, &t); + const TargetDetails defaultTargetDetails; + auto getTargetDetails = [&targetDetailsHash, &defaultTargetDetails](const QString &id) + -> const TargetDetails & { + auto it = targetDetailsHash.constFind(id); + if (it != targetDetailsHash.constEnd()) + return *it.value(); + return defaultTargetDetails; + }; + for (const FileApiDetails::Target &t : config.targets) { - const TargetDetails &td = Utils::findOrDefault(targetDetails, - Utils::equal(&TargetDetails::id, t.id)); + const TargetDetails &td = getTargetDetails(t.id); const FilePath dir = directorySourceDir(config, sourceDir, t.directory); From e78f456083a8784812af4ae55542000384e6e0a6 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 7 Oct 2021 16:58:25 +0200 Subject: [PATCH 002/117] Debugger: Use MacroExpander from RunControl instead from Kit Kit is just a subset. Change-Id: I9ddfbfeaa5eadaa2e9a1d9a4a3409c6cf8a9658e Reviewed-by: David Schulz --- src/plugins/debugger/debuggerengine.h | 2 +- src/plugins/debugger/debuggerruncontrol.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 8611e4668d6..2099bc2f959 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -195,7 +195,7 @@ public: bool isCppDebugging() const; bool isNativeMixedDebugging() const; - Utils::MacroExpander *macroExpander = nullptr; + const Utils::MacroExpander *macroExpander = nullptr; Utils::optional exitCode = {}; diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index ffece207088..8b92c7d31dc 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -885,7 +885,7 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm QTC_ASSERT(kit, return); m_runParameters.sysRoot = SysRootKitAspect::sysRoot(kit); - m_runParameters.macroExpander = kit->macroExpander(); + m_runParameters.macroExpander = runControl->macroExpander(); m_runParameters.debugger = DebuggerKitAspect::runnable(kit); m_runParameters.cppEngineType = DebuggerKitAspect::engineType(kit); From 7a76f7edbfd0dde1184e8d57e1593f08b9735660 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 23 Jun 2021 10:20:07 +0200 Subject: [PATCH 003/117] Revert "FakeVim: Also record NoVisualMode as last visual mode" This reverts commit e5dd24322fedb28592f5a741b42877da8253465c which caused QTCREATORBUG-26214. Fixes: QTCREATORBUG-26214 Change-Id: I0d285b4df8fa428201fb6c48bbbad81f8195a941 Reviewed-by: Christian Stenger --- src/plugins/fakevim/fakevimhandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 862dfc12b57..ae9cfc173f2 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -8201,9 +8201,9 @@ void FakeVimHandler::Private::saveLastVisualMode() if (isVisualMode() && g.mode == CommandMode && g.submode == NoSubMode) { setMark('<', markLessPosition()); setMark('>', markGreaterPosition()); + m_buffer->lastVisualModeInverted = anchor() > position(); + m_buffer->lastVisualMode = g.visualMode; } - m_buffer->lastVisualModeInverted = anchor() > position(); - m_buffer->lastVisualMode = g.visualMode; } QWidget *FakeVimHandler::Private::editor() const From 3395cdfd2668a4a3b9551bc16807c17e9caf1388 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 7 Oct 2021 15:05:10 +0300 Subject: [PATCH 004/117] QmlDesigner: Make form view react to node source changes properly Implicit components lose/gain node source when reparented, so we need to also potentially remove form editor items based on the node source state of the node itself in addition to the state of the parent. Node source can also change without reparenting, and it's not guaranteed the node source is up to date when nodeReparented is called, so to make sure we always end up in correct state in form editor, we do the same checks in nodeSourceChanged as we do in nodeReparented. Fixes: QDS-5230 Change-Id: Ib358ccb0db4c26e4857bad00e35930287c4149fb Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../components/formeditor/formeditorview.cpp | 56 ++++++++++++------- .../components/formeditor/formeditorview.h | 2 + 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 10e1373dde2..53c26261a08 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -339,26 +339,12 @@ static inline bool hasNodeSourceParent(const ModelNode &node) void FormEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) { - // If node is not connected to scene root, don't do anything yet to avoid duplicated effort, - // as any removal or addition will remove or add descendants as well. - if (!node.isInHierarchy()) - return; + addOrRemoveFormEditorItem(node); +} - QmlItemNode itemNode(node); - if (hasNodeSourceParent(node)) { - if (FormEditorItem *item = m_scene->itemForQmlItemNode(itemNode)) { - QList removed = scene()->itemsForQmlItemNodes(itemNode.allSubModelNodes()); - removed.append(item); - m_currentTool->itemsAboutToRemoved(removed); - removeNodeFromScene(itemNode); - } - } else if (itemNode.isValid() && node.nodeSourceType() == ModelNode::NodeWithoutSource) { - if (!m_scene->itemForQmlItemNode(itemNode)) { - setupFormEditorItemTree(itemNode); - // Simulate selection change to refresh tools - selectedNodesChanged(selectedModelNodes(), {}); - } - } +void FormEditorView::nodeSourceChanged(const ModelNode &node, const QString &newNodeSource) +{ + addOrRemoveFormEditorItem(node); } WidgetInfo FormEditorView::widgetInfo() @@ -863,6 +849,38 @@ void FormEditorView::resetNodeInstanceView() resetPuppet(); } +void FormEditorView::addOrRemoveFormEditorItem(const ModelNode &node) +{ + // If node is not connected to scene root, don't do anything yet to avoid duplicated effort, + // as any removal or addition will remove or add descendants as well. + if (!node.isInHierarchy()) + return; + + QmlItemNode itemNode(node); + + auto removeItemFromScene = [this, &itemNode]() { + if (FormEditorItem *item = m_scene->itemForQmlItemNode(itemNode)) { + QList removed = scene()->itemsForQmlItemNodes(itemNode.allSubModelNodes()); + removed.append(item); + m_currentTool->itemsAboutToRemoved(removed); + removeNodeFromScene(itemNode); + } + }; + if (hasNodeSourceParent(node)) { + removeItemFromScene(); + } else if (itemNode.isValid()) { + if (node.nodeSourceType() == ModelNode::NodeWithoutSource) { + if (!m_scene->itemForQmlItemNode(itemNode)) { + setupFormEditorItemTree(itemNode); + // Simulate selection change to refresh tools + selectedNodesChanged(selectedModelNodes(), {}); + } + } else { + removeItemFromScene(); + } + } +} + void FormEditorView::reset() { QTimer::singleShot(200, this, &FormEditorView::delayedReset); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h index 04b7d1e83ec..ca3fb72bb0a 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h @@ -70,6 +70,7 @@ public: void nodeCreated(const ModelNode &createdNode) override; void nodeAboutToBeRemoved(const ModelNode &removedNode) override; void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; + void nodeSourceChanged(const ModelNode &node, const QString &newNodeSource) override; void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override; void propertiesAboutToBeRemoved(const QList& propertyList) override; void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override; @@ -147,6 +148,7 @@ private: void createFormEditorWidget(); void temporaryBlockView(int duration = 1000); void resetNodeInstanceView(); + void addOrRemoveFormEditorItem(const ModelNode &node); QPointer m_formEditorWidget; QPointer m_scene; From 9b6f60992cadf3835a9e6d752cfe860bf0da85bc Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 8 Oct 2021 13:59:02 +0300 Subject: [PATCH 005/117] QmlDesigner: Update repeater parent when repeater properties change Any time repeater properties change, the repeater parent should be dirtied to ensure it rerenders. Often the rerender is triggered incidentally due to other triggers, but e.g. in case model value is changed to zero, or if model property is removed, no other trigger causes rerender. Also moved the repeater parent checks into QuickItemNodeInstance to avoid polluting Qt5NodeInstanceServer with such stuff. Fixes: QDS-5233 Change-Id: Idd89e23c5ad022d26f443d665dac81dc2cbb0b28 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../instances/qt5nodeinstanceserver.cpp | 42 ------------------- .../instances/qt5nodeinstanceserver.h | 2 - .../instances/quickitemnodeinstance.cpp | 37 ++++++++++++++++ .../instances/quickitemnodeinstance.h | 1 + 4 files changed, 38 insertions(+), 44 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 2e1e03fa630..9f8f5caf528 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -194,32 +193,6 @@ QList Qt5NodeInstanceServer::allItems() const return QList(); } -void Qt5NodeInstanceServer::markRepeaterParentDirty(qint32 id) const -{ - if (!hasInstanceForId(id)) - return; - - ServerNodeInstance instance = instanceForId(id); - if (!instance.isValid()) - return; - - ServerNodeInstance parentInstance = instance.parent(); - if (!parentInstance.isValid()) - return; - - // If a Repeater instance was moved/removed, the old parent must be marked dirty to rerender it - const QByteArray type("QQuickRepeater"); - if (ServerNodeInstance::isSubclassOf(instance.internalObject(), type)) - DesignerSupport::addDirty(parentInstance.rootQuickItem(), QQuickDesignerSupport::Content); - - // Repeater's parent must also be dirtied when a child of a repeater was moved/removed. - if (ServerNodeInstance::isSubclassOf(parentInstance.internalObject(), type)) { - ServerNodeInstance parentsParent = parentInstance.parent(); - if (parentsParent.isValid()) - DesignerSupport::addDirty(parentsParent.rootQuickItem(), QQuickDesignerSupport::Content); - } -} - bool Qt5NodeInstanceServer::initRhi(RenderViewData &viewData) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) @@ -550,23 +523,8 @@ void Qt5NodeInstanceServer::clearScene(const ClearSceneCommand &command) void Qt5NodeInstanceServer::reparentInstances(const ReparentInstancesCommand &command) { - const QVector &containerVector = command.reparentInstances(); - for (const ReparentContainer &container : containerVector) - markRepeaterParentDirty(container.instanceId()); - NodeInstanceServer::reparentInstances(command.reparentInstances()); startRenderTimer(); } -void Qt5NodeInstanceServer::removeInstances(const RemoveInstancesCommand &command) -{ - const QVector &idVector = command.instanceIds(); - for (const qint32 id : idVector) - markRepeaterParentDirty(id); - - NodeInstanceServer::removeInstances(command); - startRenderTimer(); -} - - } // QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h index d93ecad84ed..4af451b61ae 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h @@ -67,7 +67,6 @@ public: void createScene(const CreateSceneCommand &command) override; void clearScene(const ClearSceneCommand &command) override; void reparentInstances(const ReparentInstancesCommand &command) override; - void removeInstances(const RemoveInstancesCommand &command) override; QImage grabWindow() override; QImage grabItem(QQuickItem *item) override; @@ -80,7 +79,6 @@ protected: void resetAllItems(); void setupScene(const CreateSceneCommand &command) override; QList allItems() const; - void markRepeaterParentDirty(qint32 id) const; struct RenderViewData { QPointer window = nullptr; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index 34693cc0bcf..403ba9fbe9a 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -767,6 +767,8 @@ void QuickItemNodeInstance::reparent(const ObjectNodeInstance::Pointer &oldParen setMovable(true); } + markRepeaterParentDirty(); + ObjectNodeInstance::reparent(oldParentInstance, oldParentProperty, newParentInstance, newParentProperty); if (!newParentInstance) @@ -831,6 +833,8 @@ void QuickItemNodeInstance::setPropertyVariant(const PropertyName &name, const Q if (name == "layer.enabled" || name == "layer.effect") setAllNodesDirtyRecursive(quickItem()); + markRepeaterParentDirty(); + ObjectNodeInstance::setPropertyVariant(name, value); refresh(); @@ -850,6 +854,8 @@ void QuickItemNodeInstance::setPropertyBinding(const PropertyName &name, const Q if (name.startsWith("anchors.") && isRootNodeInstance()) return; + markRepeaterParentDirty(); + ObjectNodeInstance::setPropertyBinding(name, expression); refresh(); @@ -927,6 +933,8 @@ void QuickItemNodeInstance::resetProperty(const PropertyName &name) resetVertical(); } + markRepeaterParentDirty(); + ObjectNodeInstance::resetProperty(name); if (isInLayoutable()) @@ -1003,6 +1011,35 @@ QQuickItem *QuickItemNodeInstance::quickItem() const return static_cast(object()); } +void QuickItemNodeInstance::markRepeaterParentDirty() const +{ + const qint32 id = instanceId(); + if (id <= 0 && !isValid()) + return; + + QQuickItem *item = quickItem(); + if (!item) + return; + + QQuickItem *parentItem = item->parentItem(); + if (!parentItem) + return; + + // If a Repeater instance was changed in any way, the parent must be marked dirty to rerender it + const QByteArray type("QQuickRepeater"); + if (ServerNodeInstance::isSubclassOf(item, type)) + DesignerSupport::addDirty(parentItem, QQuickDesignerSupport::Content); + + // Repeater's parent must also be dirtied when a child of a repeater was changed + if (ServerNodeInstance::isSubclassOf(parentItem, type)) { + QQuickItem *parentsParent = parentItem->parentItem(); + if (parentsParent) + DesignerSupport::addDirty(parentsParent, QQuickDesignerSupport::Content); + } +} + + + } // namespace Internal } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h index 77d3a3fc6b5..46b22b8c9a8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h @@ -130,6 +130,7 @@ protected: double x() const; double y() const; bool checkIfRefFromEffect(qint32 id); + void markRepeaterParentDirty() const; private: //variables QPointer m_contentItem; From a40b7867f60e8823db20b2815ddf0336783ffd37 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 5 Oct 2021 12:27:36 +0200 Subject: [PATCH 006/117] ClangCodeModel: Optimize getAstPath() Profiling has shown that this function is a hotspot. Luckily, it can be easily sped up by taking advantage of the fact that the AST nodes are (mostly) sorted by range, allowing us to employ a binary search when looking for a given range. Change-Id: I950c150543ff68b975d36c6fb652d366b93ea3b2 Reviewed-by: David Schulz --- src/libs/languageserverprotocol/lsptypes.cpp | 10 +++- src/libs/languageserverprotocol/lsptypes.h | 9 ++++ src/plugins/clangcodemodel/clangdclient.cpp | 50 +++++++++++++++---- .../tst_languageserverprotocol.cpp | 6 +-- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp index 820f4b6c4b4..65651366a3d 100644 --- a/src/libs/languageserverprotocol/lsptypes.cpp +++ b/src/libs/languageserverprotocol/lsptypes.cpp @@ -293,6 +293,14 @@ QTextCursor Position::toTextCursor(QTextDocument *doc) const return cursor; } +Position Position::withOffset(int offset, const QTextDocument *doc) const +{ + int line; + int character; + Utils::Text::convertPosition(doc, toPositionInDocument(doc) + offset, &line, &character); + return Position(line - 1, character - 1); +} + Range::Range(const Position &start, const Position &end) { setStart(start); @@ -323,7 +331,7 @@ bool Range::contains(const Range &other) const bool Range::overlaps(const Range &range) const { - return end() > range.start() && start() < range.end(); + return !isLeftOf(range) && !range.isLeftOf(*this); } QString expressionForGlob(QString globPattern) diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h index 7cbe0455637..7bd004ca6cc 100644 --- a/src/libs/languageserverprotocol/lsptypes.h +++ b/src/libs/languageserverprotocol/lsptypes.h @@ -90,6 +90,7 @@ public: int toPositionInDocument(const QTextDocument *doc) const; QTextCursor toTextCursor(QTextDocument *doc) const; + Position withOffset(int offset, const QTextDocument *doc) const; }; inline bool operator<(const Position &first, const Position &second) @@ -103,6 +104,11 @@ inline bool operator>(const Position &first, const Position &second) return second < first; } +inline bool operator>=(const Position &first, const Position &second) +{ + return !(first < second); +} + inline bool operator<=(const Position &first, const Position &second) { return !(first > second); @@ -124,9 +130,12 @@ public: Position end() const { return typedValue(endKey); } void setEnd(const Position &end) { insert(endKey, end); } + bool isEmpty() const { return start() == end(); } bool contains(const Position &pos) const { return start() <= pos && pos <= end(); } bool contains(const Range &other) const; bool overlaps(const Range &range) const; + bool isLeftOf(const Range &other) const + { return isEmpty() || other.isEmpty() ? end() < other.start() : end() <= other.start(); } bool isValid() const override { return JsonObject::contains(startKey) && JsonObject::contains(endKey); } diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 5b3e76bee8b..6d4dac1459f 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -298,6 +298,7 @@ static QList getAstPath(const AstNode &root, const Range &range) QList path; QList queue{root}; bool isRoot = true; + while (!queue.isEmpty()) { AstNode curNode = queue.takeFirst(); if (!isRoot && !curNode.hasRange()) @@ -309,13 +310,39 @@ static QList getAstPath(const AstNode &root, const Range &range) const auto children = curNode.children(); if (!children) break; - queue = children.value(); + if (curNode.kind() == "Function" || curNode.role() == "expression") { + // Functions and expressions can contain implicit nodes that make the list unsorted. + // They cannot be ignored, as we need to consider them in certain contexts. + // Therefore, the binary search cannot be used here. + queue = *children; + } else { + queue.clear(); + + // Class and struct nodes can contain implicit constructors, destructors and + // operators, which appear at the end of the list, but whose range is the same + // as the class name. Therefore, we must force them not to compare less to + // anything else. + static const auto leftOfRange = [](const AstNode &node, const Range &range) { + return node.range().isLeftOf(range) && !node.arcanaContains(" implicit "); + }; + + for (auto it = std::lower_bound(children->cbegin(), children->cend(), range, + leftOfRange); + it != children->cend() && !range.isLeftOf(it->range()); ++it) { + queue << *it; + } + } } isRoot = false; } return path; } +static QList getAstPath(const AstNode &root, const Position &pos) +{ + return getAstPath(root, Range(pos, pos)); +} + static Usage::Type getUsageType(const QList &path) { bool potentialWrite = false; @@ -1643,7 +1670,7 @@ void ClangdClient::findLocalUsages(TextDocument *document, const QTextCursor &cu } const Position linkPos(link.targetLine - 1, link.targetColumn); - const QList astPath = getAstPath(ast, Range(linkPos, linkPos)); + const QList astPath = getAstPath(ast, linkPos); bool isVar = false; for (auto it = astPath.rbegin(); it != astPath.rend(); ++it) { if (it->role() == "declaration" && it->kind() == "Function") { @@ -2222,13 +2249,17 @@ static void semanticHighlighter(QFutureInterface &future, } const QTextDocument doc(docContents); - const auto isOutputParameter = [&ast](const ExpandedSemanticToken &token) { + const auto tokenRange = [&doc](const ExpandedSemanticToken &token) { + const Position startPos(token.line - 1, token.column - 1); + const Position endPos = startPos.withOffset(token.length, &doc); + return Range(startPos, endPos); + }; + const auto isOutputParameter = [&ast, &doc, &tokenRange](const ExpandedSemanticToken &token) { if (token.modifiers.contains("usedAsMutableReference")) return true; if (token.type != "variable" && token.type != "property" && token.type != "parameter") return false; - const Position pos(token.line - 1, token.column - 1); - const QList path = getAstPath(ast, Range(pos, pos)); + const QList path = getAstPath(ast, tokenRange(token)); if (path.size() < 2) return false; if (path.last().hasConstType()) @@ -2249,7 +2280,8 @@ static void semanticHighlighter(QFutureInterface &future, }; const std::function toResult - = [&ast, &isOutputParameter, &clangdVersion](const ExpandedSemanticToken &token) { + = [&ast, &isOutputParameter, &clangdVersion, &tokenRange] + (const ExpandedSemanticToken &token) { TextStyles styles; if (token.type == "variable") { if (token.modifiers.contains("functionScope")) { @@ -2263,8 +2295,7 @@ static void semanticHighlighter(QFutureInterface &future, } else if (token.type == "function" || token.type == "method") { styles.mainStyle = token.modifiers.contains("virtual") ? C_VIRTUAL_METHOD : C_FUNCTION; if (ast.isValid()) { - const Position pos(token.line - 1, token.column - 1); - const QList path = getAstPath(ast, Range(pos, pos)); + const QList path = getAstPath(ast, tokenRange(token)); if (path.length() > 1) { const AstNode declNode = path.at(path.length() - 2); if (declNode.kind() == "Function" || declNode.kind() == "CXXMethod") { @@ -2283,8 +2314,7 @@ static void semanticHighlighter(QFutureInterface &future, // clang hardly ever differentiates between constructors and the associated class, // whereas we highlight constructors as functions. if (ast.isValid()) { - const Position pos(token.line - 1, token.column - 1); - const QList path = getAstPath(ast, Range(pos, pos)); + const QList path = getAstPath(ast, tokenRange(token)); if (!path.isEmpty()) { if (path.last().kind() == "CXXConstructor") { if (!path.last().arcanaContains("implicit")) diff --git a/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp b/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp index db994a3c5bf..20fb60cd538 100644 --- a/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp +++ b/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp @@ -552,7 +552,7 @@ void tst_LanguageServerProtocol::range_data() auto pos = [](int pos) { return Position(0, pos); }; QTest::newRow("both ranges empty") - << Range(pos(0), pos(0)) << Range(pos(0), pos(0)) << false << true << true; + << Range(pos(0), pos(0)) << Range(pos(0), pos(0)) << true << true << true; QTest::newRow("equal ranges") << Range(pos(0), pos(1)) << Range(pos(0), pos(1)) << true << true << true; QTest::newRow("r1 before r2") @@ -562,7 +562,7 @@ void tst_LanguageServerProtocol::range_data() QTest::newRow("r1 starts before r2 overlapping") << Range(pos(0), pos(2)) << Range(pos(1), pos(3)) << true << false << false; QTest::newRow("empty r1 on r2 start") - << Range(pos(0), pos(0)) << Range(pos(0), pos(1)) << false << false << true; + << Range(pos(0), pos(0)) << Range(pos(0), pos(1)) << true << false << true; QTest::newRow("r1 inside r2 equal start") << Range(pos(0), pos(1)) << Range(pos(0), pos(2)) << true << false << true; QTest::newRow("r1 inside r2 equal start") @@ -576,7 +576,7 @@ void tst_LanguageServerProtocol::range_data() QTest::newRow("r1 ends after r2 overlapping") << Range(pos(1), pos(3)) << Range(pos(0), pos(2)) << true << false << false; QTest::newRow("empty r1 on r2 end") - << Range(pos(1), pos(1)) << Range(pos(0), pos(1)) << false << false << true; + << Range(pos(1), pos(1)) << Range(pos(0), pos(1)) << true << false << true; QTest::newRow("r1 adjacent after r2") << Range(pos(1), pos(2)) << Range(pos(0), pos(1)) << false << false << false; QTest::newRow("r1 behind r2") From 0a2b5046639bd3d3c318a7f1c9e8ac64bc3cfc76 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 7 Oct 2021 16:15:08 +0200 Subject: [PATCH 007/117] CppEditor: Add warning label to clangd settings page So people with older installations know right away that they can't expect full functionality. Change-Id: I8cceb2c88ba1622fa37fb88fc0b96253b6c13a06 Reviewed-by: David Schulz --- .../cppeditor/cppcodemodelsettingspage.cpp | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 2c775e38437..1c6621e070b 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -33,11 +33,14 @@ #include #include +#include #include +#include #include #include #include +#include namespace CppEditor::Internal { @@ -197,6 +200,7 @@ public: QSpinBox threadLimitSpinBox; QSpinBox documentUpdateThreshold; Utils::PathChooser clangdChooser; + Utils::InfoLabel versionWarningLabel; }; ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsData) @@ -230,6 +234,7 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD const auto formLayout = new QFormLayout; const auto chooserLabel = new QLabel(tr("Path to executable:")); formLayout->addRow(chooserLabel, &d->clangdChooser); + formLayout->addRow(QString(), &d->versionWarningLabel); const auto indexingLabel = new QLabel(tr("Enable background indexing:")); formLayout->addRow(indexingLabel, &d->indexingCheckBox); const auto threadLimitLayout = new QHBoxLayout; @@ -251,11 +256,58 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD indexingLabel->setEnabled(checked); d->indexingCheckBox.setEnabled(checked); d->threadLimitSpinBox.setEnabled(checked); + d->versionWarningLabel.setEnabled(checked); }; connect(&d->useClangdCheckBox, &QCheckBox::toggled, toggleEnabled); toggleEnabled(d->useClangdCheckBox.isChecked()); d->threadLimitSpinBox.setEnabled(d->useClangdCheckBox.isChecked()); + d->versionWarningLabel.setType(Utils::InfoLabel::Warning); + const auto updateWarningLabel = [this] { + class WarningLabelSetter { + public: + WarningLabelSetter(QLabel &label) : m_label(label) { m_label.clear(); } + ~WarningLabelSetter() { m_label.setVisible(!m_label.text().isEmpty()); } + void setWarning(const QString &text) { m_label.setText(text); } + private: + QLabel &m_label; + }; + WarningLabelSetter labelSetter(d->versionWarningLabel); + + if (!d->clangdChooser.isValid()) + return; + const Utils::FilePath clangdPath = d->clangdChooser.filePath(); + Utils::QtcProcess clangdProc; + clangdProc.setCommand({clangdPath, {"--version"}}); + clangdProc.start(); + if (!clangdProc.waitForStarted() || !clangdProc.waitForFinished()) { + labelSetter.setWarning(tr("Failed to retrieve clangd version: %1") + .arg(clangdProc.exitMessage())); + return; + } + const QString output = clangdProc.allOutput(); + static const QString versionPrefix = "clangd version "; + const int prefixOffset = output.indexOf(versionPrefix); + QVersionNumber clangdVersion; + if (prefixOffset != -1) { + clangdVersion = QVersionNumber::fromString(output.mid(prefixOffset + + versionPrefix.length())); + } + if (clangdVersion.isNull()) { + labelSetter.setWarning(tr("Failed to retrieve clangd version: " + "Unexpected clangd output.")); + return; + } + if (clangdVersion < QVersionNumber(13)) { + labelSetter.setWarning(tr("The clangd version is %1, but %2 or greater is " + "recommended for full functionality.") + .arg(clangdVersion.toString()).arg(13)); + return; + } + }; + connect(&d->clangdChooser, &Utils::PathChooser::pathChanged, this, updateWarningLabel); + updateWarningLabel(); + connect(&d->useClangdCheckBox, &QCheckBox::toggled, this, &ClangdSettingsWidget::settingsDataChanged); connect(&d->indexingCheckBox, &QCheckBox::toggled, From ce34ffdc21ac4928f1b687c36bf11fc4db79b581 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 8 Oct 2021 10:15:51 +0200 Subject: [PATCH 008/117] ClangCodeModel: Do not trigger snippets ... in strings or comments with clangd. Change-Id: Ic16e94051018e91f273fafe2ec90d5395e4cc07a Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 67 +++++++++++++++------ src/plugins/cppeditor/cppprojectfile.cpp | 14 +++++ src/plugins/cppeditor/cppprojectfile.h | 1 + 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 6d4dac1459f..01bd5b6c2a7 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -35,9 +35,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -712,20 +714,12 @@ private: case CustomAssistMode::Preprocessor: static QIcon macroIcon = Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Macro); for (const QString &completion - : CppEditor::CppCompletionAssistProcessor::preprocessorCompletions()) + : CppEditor::CppCompletionAssistProcessor::preprocessorCompletions()) { completions << createItem(completion, macroIcon); - const CppEditor::ProjectFile::Kind fileType - = CppEditor::ProjectFile::classify(interface->filePath().toString()); - switch (fileType) { - case CppEditor::ProjectFile::ObjCHeader: - case CppEditor::ProjectFile::ObjCXXHeader: - case CppEditor::ProjectFile::ObjCSource: - case CppEditor::ProjectFile::ObjCXXSource: - completions << createItem("import", macroIcon); - break; - default: - break; } + if (CppEditor::ProjectFile::isObjC(interface->filePath().toString())) + completions << createItem("import", macroIcon); + break; } GenericProposalModelPtr model(new GenericProposalModel); model->loadContent(completions); @@ -1057,12 +1051,14 @@ public: ClangdCompletionAssistProvider(ClangdClient *client); private: - IAssistProcessor *createProcessor(const AssistInterface *assistInterface) const override; + IAssistProcessor *createProcessor(const AssistInterface *interface) const override; int activationCharSequenceLength() const override { return 3; } bool isActivationCharSequence(const QString &sequence) const override; bool isContinuationChar(const QChar &c) const override; + bool isInCommentOrString(const AssistInterface *interface) const; + ClangdClient * const m_client; }; @@ -2573,10 +2569,10 @@ ClangdClient::ClangdCompletionAssistProvider::ClangdCompletionAssistProvider(Cla {} IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor( - const AssistInterface *assistInterface) const + const AssistInterface *interface) const { - ClangCompletionContextAnalyzer contextAnalyzer(assistInterface->textDocument(), - assistInterface->position(), false, {}); + ClangCompletionContextAnalyzer contextAnalyzer(interface->textDocument(), + interface->position(), false, {}); contextAnalyzer.analyze(); switch (contextAnalyzer.completionAction()) { case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: @@ -2595,7 +2591,7 @@ IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor( default: break; } - const QString snippetsGroup = contextAnalyzer.addSnippets() + const QString snippetsGroup = contextAnalyzer.addSnippets() && !isInCommentOrString(interface) ? CppEditor::Constants::CPP_SNIPPETS_GROUP_ID : QString(); return new ClangdCompletionAssistProcessor(m_client, snippetsGroup); @@ -2628,6 +2624,43 @@ bool ClangdClient::ClangdCompletionAssistProvider::isContinuationChar(const QCha return CppEditor::isValidIdentifierChar(c); } +bool ClangdClient::ClangdCompletionAssistProvider::isInCommentOrString( + const AssistInterface *interface) const +{ + QTextCursor tc(interface->textDocument()); + tc.setPosition(interface->position()); + + SimpleLexer tokenize; + tokenize.setSkipComments(false); + const Tokens &tokens = tokenize(tc.block().text(), + BackwardsScanner::previousBlockState(tc.block())); + const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); + const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); + + if (tk.isComment()) + return true; + if (!tk.isLiteral()) + return false; + if (tokens.size() == 3 && tokens.at(0).kind() == T_POUND + && tokens.at(1).kind() == T_IDENTIFIER) { + const QString &line = tc.block().text(); + const Token &idToken = tokens.at(1); + QStringView identifier = idToken.utf16charsEnd() > line.size() + ? QStringView(line).mid( + idToken.utf16charsBegin()) + : QStringView(line) + .mid(idToken.utf16charsBegin(), + idToken.utf16chars()); + if (identifier == QLatin1String("include") + || identifier == QLatin1String("include_next") + || (CppEditor::ProjectFile::isObjC(interface->filePath().toString()) + && identifier == QLatin1String("import"))) { + return false; + } + } + return true; +} + void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, int /*basePosition*/) const { diff --git a/src/plugins/cppeditor/cppprojectfile.cpp b/src/plugins/cppeditor/cppprojectfile.cpp index fa3bf8c0238..58196521ca1 100644 --- a/src/plugins/cppeditor/cppprojectfile.cpp +++ b/src/plugins/cppeditor/cppprojectfile.cpp @@ -87,6 +87,20 @@ bool ProjectFile::isAmbiguousHeader(const QString &filePath) return filePath.endsWith(".h"); } +bool ProjectFile::isObjC(const QString &filePath) +{ + const Kind kind = classify(filePath); + switch (kind) { + case CppEditor::ProjectFile::ObjCHeader: + case CppEditor::ProjectFile::ObjCXXHeader: + case CppEditor::ProjectFile::ObjCSource: + case CppEditor::ProjectFile::ObjCXXSource: + return true; + default: + return false; + } +} + ProjectFile::Kind ProjectFile::sourceForHeaderKind(ProjectFile::Kind kind) { ProjectFile::Kind sourceKind; diff --git a/src/plugins/cppeditor/cppprojectfile.h b/src/plugins/cppeditor/cppprojectfile.h index 078b93cce9e..1bd80fdf65c 100644 --- a/src/plugins/cppeditor/cppprojectfile.h +++ b/src/plugins/cppeditor/cppprojectfile.h @@ -61,6 +61,7 @@ public: static bool isC(Kind kind); static bool isCxx(Kind kind); static bool isAmbiguousHeader(const QString &filePath); + static bool isObjC(const QString &filePath); bool isHeader() const; bool isSource() const; From 05fa3b06e54914043da767de14bff1ed2ee2cc95 Mon Sep 17 00:00:00 2001 From: Tapani Mattila Date: Thu, 30 Sep 2021 19:01:03 +0300 Subject: [PATCH 009/117] Wizards: Enable using default values for json wizards by using json "imports" Task-number: QDS-5214 Change-Id: I67ba3aef15edb3935fb9aeb6b317348de3f60dca Reviewed-by: Alessandro Portale --- .../jsonwizard/jsonwizardfactory.cpp | 154 +++++++++++++++++- .../jsonwizard/jsonwizardfactory.h | 6 + 2 files changed, 152 insertions(+), 8 deletions(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index 9aa16ff0513..f61836cffa1 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -86,6 +86,7 @@ const char PAGE_SHORT_TITLE_KEY[] = "trShortTitle"; const char PAGE_INDEX_KEY[] = "index"; const char OPTIONS_KEY[] = "options"; const char PLATFORM_INDEPENDENT_KEY[] = "platformIndependent"; +const char DEFAULT_VALUES[] = "defaultValues"; static QList s_pageFactories; static QList s_generatorFactories; @@ -152,7 +153,122 @@ static JsonWizardFactory::Generator parseGenerator(const QVariant &value, QStrin return gen; } -static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMessage) +//FIXME: createWizardFactories() has an almost identical loop. Make the loop return the results instead of +//internal processing and create a separate function for it. Then process the results in +//loadDefaultValues() and createWizardFactories() +QVariantMap JsonWizardFactory::loadDefaultValues(const QString &fileName) +{ + QString verboseLog; + + if (fileName.isEmpty()) { + return {}; + } + + QList result; + foreach (const Utils::FilePath &path, searchPaths()) { + if (path.isEmpty()) + continue; + + FilePath dir = FilePath::fromString(path.toString()); + if (!dir.exists()) { + if (verbose()) + verboseLog.append(tr("Path \"%1\" does not exist when checking Json wizard search paths.\n") + .arg(path.toUserOutput())); + continue; + } + + const QDir::Filters filters = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; + FilePaths dirs = dir.dirEntries(filters); + + while (!dirs.isEmpty()) { + const FilePath current = dirs.takeFirst(); + if (verbose()) + verboseLog.append(tr("Checking \"%1\" for %2.\n") + .arg(QDir::toNativeSeparators(current.absolutePath().toString())) + .arg(fileName)); + if (current.pathAppended(fileName).exists()) { + QFile configFile(current.pathAppended(fileName).toString()); + configFile.open(QIODevice::ReadOnly); + QJsonParseError error; + const QByteArray fileData = configFile.readAll(); + const QJsonDocument json = QJsonDocument::fromJson(fileData, &error); + configFile.close(); + + if (error.error != QJsonParseError::NoError) { + int line = 1; + int column = 1; + for (int i = 0; i < error.offset; ++i) { + if (fileData.at(i) == '\n') { + ++line; + column = 1; + } else { + ++column; + } + } + verboseLog.append(tr("* Failed to parse \"%1\":%2:%3: %4\n") + .arg(configFile.fileName()) + .arg(line).arg(column) + .arg(error.errorString())); + continue; + } + + if (!json.isObject()) { + verboseLog.append(tr("* Did not find a JSON object in \"%1\".\n") + .arg(configFile.fileName())); + continue; + } + + if (verbose()) + verboseLog.append(tr("* Configuration found and parsed.\n")); + + return json.object().toVariantMap(); + } + FilePaths subDirs = current.dirEntries(filters); + if (!subDirs.isEmpty()) { + // There is no QList::prepend(QList)... + dirs.swap(subDirs); + dirs.append(subDirs); + } else if (verbose()) { + verboseLog.append(tr("JsonWizard: \"%1\" not found\n").arg(fileName)); + } + } + } + + if (verbose()) { // Print to output pane for Windows. + qWarning("%s", qPrintable(verboseLog)); + Core::MessageManager::writeDisrupting(verboseLog); + } + + return {}; +} + +QVariant JsonWizardFactory::mergeDataValueMaps(const QVariant &valueMap, const QVariant &defaultValueMap) +{ + QVariantMap retVal; + + retVal.insert(defaultValueMap.toMap()); + retVal.insert(valueMap.toMap()); + + return retVal; +} + +QVariant JsonWizardFactory::getDataValue(const QLatin1String &key, const QVariantMap &valueSet, + const QVariantMap &defaultValueSet, const QVariant ¬ExistValue) +{ + QVariant retVal = {}; + + if ((valueSet.contains(key) && valueSet.value(key).type() == QVariant::Map) || + (defaultValueSet.contains(key) && defaultValueSet.value(key).type() == QVariant::Map)) { + retVal = mergeDataValueMaps(valueSet.value(key), defaultValueSet.value(key)); + } else { + QVariant defaultValue = defaultValueSet.value(key, notExistValue); + retVal = valueSet.value(key, defaultValue); + } + + return retVal; +} + +JsonWizardFactory::Page JsonWizardFactory::parsePage(const QVariant &value, QString *errorMessage) { JsonWizardFactory::Page p; @@ -162,7 +278,12 @@ static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMe } const QVariantMap data = value.toMap(); - const QString strVal = data.value(QLatin1String(TYPE_ID_KEY)).toString(); + QString defaultValueFile = data.value(QLatin1String(DEFAULT_VALUES)).toString(); + if (!defaultValueFile.isEmpty()) + defaultValueFile.append(QLatin1String(".json")); + const QVariantMap defaultData = loadDefaultValues(defaultValueFile); + + const QString strVal = getDataValue(QLatin1String(TYPE_ID_KEY), data, defaultData).toString(); if (strVal.isEmpty()) { *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Page has no typeId set."); return p; @@ -179,21 +300,35 @@ static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMe return p; } - const QString title = JsonWizardFactory::localizedString(data.value(QLatin1String(DISPLAY_NAME_KEY))); - const QString subTitle = JsonWizardFactory::localizedString(data.value(QLatin1String(PAGE_SUB_TITLE_KEY))); - const QString shortTitle = JsonWizardFactory::localizedString(data.value(QLatin1String(PAGE_SHORT_TITLE_KEY))); + const QString title = JsonWizardFactory::localizedString(getDataValue(QLatin1String(DISPLAY_NAME_KEY), data, defaultData)); + const QString subTitle = JsonWizardFactory::localizedString(getDataValue(QLatin1String(PAGE_SUB_TITLE_KEY), data, defaultData)); + const QString shortTitle = JsonWizardFactory::localizedString(getDataValue(QLatin1String(PAGE_SHORT_TITLE_KEY), data, defaultData)); bool ok; - int index = data.value(QLatin1String(PAGE_INDEX_KEY), -1).toInt(&ok); + int index = getDataValue(QLatin1String(PAGE_INDEX_KEY), data, defaultData, -1).toInt(&ok); if (!ok) { *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Page with typeId \"%1\" has invalid \"index\".") .arg(typeId.toString()); return p; } - QVariant enabled = data.value(QLatin1String(ENABLED_EXPRESSION_KEY), true); + QVariant enabled = getDataValue(QLatin1String(ENABLED_EXPRESSION_KEY), data, defaultData, true); + + QVariant specifiedSubData = data.value(QLatin1String(DATA_KEY)); + QVariant defaultSubData = defaultData.value(QLatin1String(DATA_KEY)); + QVariant subData; + + if (specifiedSubData.isNull()) { + subData = defaultSubData; + } else if (specifiedSubData.type() == QVariant::Map) { + QVariantMap subDataMap; + subDataMap.insert(defaultSubData.toMap()); + subDataMap.insert(specifiedSubData.toMap()); + subData = subDataMap; + } else if (specifiedSubData.type() == QVariant::List) { + subData = specifiedSubData; + } - QVariant subData = data.value(QLatin1String(DATA_KEY)); if (!factory->validateData(typeId, subData, errorMessage)) return p; @@ -208,6 +343,9 @@ static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMe return p; } +//FIXME: loadDefaultValues() has an almost identical loop. Make the loop return the results instead of +//internal processing and create a separate function for it. Then process the results in +//loadDefaultValues() and loadDefaultValues() QList JsonWizardFactory::createWizardFactories() { QString errorMessage; diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h index c3c6c5bd343..d69aaa00f0b 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h @@ -100,6 +100,12 @@ private: static void destroyAllFactories(); bool initialize(const QVariantMap &data, const Utils::FilePath &baseDir, QString *errorMessage); + JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMessage); + QVariantMap loadDefaultValues(const QString &fileName); + QVariant getDataValue(const QLatin1String &key, const QVariantMap &valueSet, + const QVariantMap &defaultValueSet, const QVariant ¬ExistValue={}); + QVariant mergeDataValueMaps(const QVariant &valueMap, const QVariant &defaultValueMap); + QVariant m_enabledExpression; Utils::FilePath m_wizardDir; QList m_generators; From 6669a9e44223ac776beaabd8da8c985cba7d5017 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 11 Oct 2021 11:40:36 +0200 Subject: [PATCH 010/117] CppEditor: Add missing namespace Like the comment says. Amends 284817fae6. Task-number: QTCREATORBUG-26304 Change-Id: I6cee9d84cedafa02dce14372e65672731e3e5cfc Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppprojectupdater.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppprojectupdater.h b/src/plugins/cppeditor/cppprojectupdater.h index 165ec279100..b716ef31836 100644 --- a/src/plugins/cppeditor/cppprojectupdater.h +++ b/src/plugins/cppeditor/cppprojectupdater.h @@ -47,7 +47,7 @@ public: CppProjectUpdaterFactory(); // keep the namespace, for the type name in the invokeMethod call - Q_INVOKABLE CppProjectUpdaterInterface *create(); + Q_INVOKABLE CppEditor::CppProjectUpdaterInterface *create(); }; } // namespace Internal From d1b62588c50aa6aaeb9356b9baa3255c40a65a5b Mon Sep 17 00:00:00 2001 From: Tapani Mattila Date: Wed, 6 Oct 2021 12:35:52 +0300 Subject: [PATCH 011/117] Add action to generate CMake files for QML projects Task-number: QDS-5140 Change-Id: I56d2d3d9efce4bea1281eb60a059119f5b29c02c Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../qmldesigner/generatecmakelists.cpp | 271 ++++++++++++++++++ src/plugins/qmldesigner/generatecmakelists.h | 45 +++ src/plugins/qmldesigner/qmldesignerplugin.cpp | 3 + src/plugins/qmldesigner/qmldesignerplugin.pri | 2 + src/plugins/qmldesigner/qmldesignerplugin.qbs | 2 + 6 files changed, 324 insertions(+) create mode 100644 src/plugins/qmldesigner/generatecmakelists.cpp create mode 100644 src/plugins/qmldesigner/generatecmakelists.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index ce73af5161a..cee0c2e369f 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -27,6 +27,7 @@ add_qtc_plugin(QmlDesigner documentmanager.cpp documentmanager.h documentwarningwidget.cpp documentwarningwidget.h generateresource.cpp generateresource.h + generatecmakelists.cpp generatecmakelists.h openuiqmlfiledialog.cpp openuiqmlfiledialog.h openuiqmlfiledialog.ui qmldesignerconstants.h qmldesignericons.h diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp new file mode 100644 index 00000000000..d7dc13fd5bd --- /dev/null +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** 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 "generatecmakelists.h" + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace Utils; + +namespace QmlDesigner { +namespace GenerateCmakeLists { + +const QDir::Filters FILES_ONLY = QDir::Files; +const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; + +const char CMAKEFILENAME[] = "CMakeLists.txt"; +const char QMLDIRFILENAME[] = "qmldir"; + +void generateMenuEntry() +{ + Core::ActionContainer *buildMenu = + Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT); + const Core::Context projectCntext(QmlProjectManager::Constants::QML_PROJECT_ID); + auto action = new QAction("Generate CMakeLists.txt files"); + QObject::connect(action, &QAction::triggered, GenerateCmakeLists::onGenerateCmakeLists); + Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateCMakeLists"); + buildMenu->addAction(cmd, ProjectExplorer::Constants::G_BUILD_RUN); + + action->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr); + QObject::connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::startupProjectChanged, [action]() { + action->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr); + }); +} + +void onGenerateCmakeLists() +{ + generateMainCmake(ProjectExplorer::SessionManager::startupProject()->projectDirectory()); +} + +QStringList processDirectory(const FilePath &dir) +{ + QStringList moduleNames; + + FilePaths files = dir.dirEntries(FILES_ONLY); + for (FilePath &file : files) { + if (!file.fileName().compare(CMAKEFILENAME)) + files.removeAll(file); + } + + if (files.isEmpty()) { + generateSubdirCmake(dir); + FilePaths subDirs = dir.dirEntries(DIRS_ONLY); + for (FilePath &subDir : subDirs) { + QStringList subDirModules = processDirectory(subDir); + moduleNames.append(subDirModules); + } + } + else { + QString moduleName = generateModuleCmake(dir); + if (!moduleName.isEmpty()) { + moduleNames.append(moduleName); + } + } + + return moduleNames; +} + +const char MAINFILE_REQUIRED_VERSION[] = "cmake_minimum_required(VERSION 3.18)\n\n"; +const char MAINFILE_PROJECT[] = "project(%1 LANGUAGES CXX)\n\n"; +const char MAINFILE_CMAKE_OPTIONS[] = "set(CMAKE_INCLUDE_CURRENT_DIR ON)\nset(CMAKE_AUTOMOC ON)\n\n"; +const char MAINFILE_PACKAGES[] = "find_package(Qt6 COMPONENTS Gui Qml Quick)\n"; +const char MAINFILE_LIBRARIES[] = "set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)\n\n"; +const char MAINFILE_CPP[] = "add_executable(%1 main.cpp)\n\n"; +const char MAINFILE_MAINMODULE[] = "qt6_add_qml_module(%1\n\tURI \"Main\"\n\tVERSION 1.0\n\tNO_PLUGIN\n\tQML_FILES main.qml\n)\n\n"; +const char MAINFILE_LINK_LIBRARIES[] = "target_link_libraries(%1 PRIVATE\n\tQt${QT_VERSION_MAJOR}::Core\n\tQt${QT_VERSION_MAJOR}::Gui\n\tQt${QT_VERSION_MAJOR}::Quick\n\tQt${QT_VERSION_MAJOR}::Qml\n)\n\n"; + +const char ADD_SUBDIR[] = "add_subdirectory(%1)\n"; + +void generateMainCmake(const FilePath &rootDir) +{ + //TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all. + QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); + + FilePaths subDirs = rootDir.dirEntries(DIRS_ONLY); + + QString fileContent; + fileContent.append(MAINFILE_REQUIRED_VERSION); + fileContent.append(QString(MAINFILE_PROJECT).arg(projectName)); + fileContent.append(MAINFILE_CMAKE_OPTIONS); + fileContent.append(MAINFILE_PACKAGES); + fileContent.append(QString(MAINFILE_CPP).arg(projectName)); + fileContent.append(QString(MAINFILE_MAINMODULE).arg(projectName)); + fileContent.append(MAINFILE_LIBRARIES); + + for (FilePath &subDir : subDirs) { + QStringList subDirModules = processDirectory(subDir); + if (!subDirModules.isEmpty()) + fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); + } + fileContent.append("\n"); + + fileContent.append(QString(MAINFILE_LINK_LIBRARIES).arg(projectName)); + + createCmakeFile(rootDir, fileContent); +} + +const char MODULEFILE_PROPERTY_SINGLETON[] = "QT_QML_SINGLETON_TYPE"; +const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n\tPROPERTIES\n\t\t%2 %3\n)\n\n"; +const char MODULEFILE_CREATE_MODULE[] = "qt6_add_qml_module(%1\n\tURI \"%1\"\n\tVERSION 1.0\n%2)\n\n"; + + +QString generateModuleCmake(const FilePath &dir) +{ + QString fileContent; + const QStringList qmlFilesOnly("*.qml"); + const QStringList qmldirFilesOnly(QMLDIRFILENAME); + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + + FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY); + if (!qmldirFileList.isEmpty()) { + QStringList singletons = getSingletonsFromQmldirFile(qmldirFileList.first()); + for (QString &singleton : singletons) { + fileContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true")); + } + } + + FilePaths qmlFileList = dir.dirEntries(qmlFilesOnly, FILES_ONLY); + QString qmlFiles; + for (FilePath &qmlFile : qmlFileList) { + if (project->isKnownFile(qmlFile)) + qmlFiles.append(QString("\t\t%1\n").arg(qmlFile.fileName())); + } + + QStringList resourceFileList = getDirectoryTreeResources(dir); + QString resourceFiles; + for (QString &resourceFile : resourceFileList) { + resourceFiles.append(QString("\t\t%1\n").arg(resourceFile)); + } + + QString moduleContent; + if (!qmlFiles.isEmpty()) { + moduleContent.append(QString("\tQML_FILES\n%1").arg(qmlFiles)); + } + if (!resourceFiles.isEmpty()) { + moduleContent.append(QString("\tRESOURCES\n%1").arg(resourceFiles)); + } + + QString moduleName = dir.fileName(); + + fileContent.append(QString(MODULEFILE_CREATE_MODULE).arg(moduleName).arg(moduleContent)); + + createCmakeFile(dir, fileContent); + + return moduleName; +} + +void generateSubdirCmake(const FilePath &dir) +{ + QString fileContent; + FilePaths subDirs = dir.dirEntries(DIRS_ONLY); + + for (FilePath &subDir : subDirs) { + fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); + } + + createCmakeFile(dir, fileContent); +} + +QStringList getSingletonsFromQmldirFile(const FilePath &filePath) +{ + QStringList singletons; + QFile f(filePath.toString()); + f.open(QIODevice::ReadOnly); + QTextStream stream(&f); + + while (!stream.atEnd()) { + QString line = stream.readLine(); + if (line.startsWith("singleton", Qt::CaseInsensitive)) { + QStringList tokenizedLine = line.split(QRegularExpression("\\s+")); + QString fileName = tokenizedLine.last(); + if (fileName.endsWith(".qml", Qt::CaseInsensitive)) { + singletons.append(fileName); + } + } + } + + f.close(); + + return singletons; +} + +QStringList getDirectoryTreeResources(const FilePath &dir) +{ + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + QStringList resourceFileList; + + FilePaths thisDirFiles = dir.dirEntries(FILES_ONLY); + for (FilePath &file : thisDirFiles) { + if (!isFileBlacklisted(file.fileName()) && + !file.fileName().endsWith(".qml", Qt::CaseInsensitive) && + project->isKnownFile(file)) { + resourceFileList.append(file.fileName()); + } + } + + FilePaths subDirsList = dir.dirEntries(DIRS_ONLY); + for (FilePath &subDir : subDirsList) { + QStringList subDirResources = getDirectoryTreeResources(subDir); + for (QString &resource : subDirResources) { + resourceFileList.append(subDir.fileName().append('/').append(resource)); + } + + } + + return resourceFileList; +} + +void createCmakeFile(const FilePath &dir, const QString &content) +{ + FilePath filePath = dir.pathAppended(CMAKEFILENAME); + QFile cmakeFile(filePath.toString()); + cmakeFile.open(QIODevice::WriteOnly); + QTextStream stream(&cmakeFile); + stream << content; + cmakeFile.close(); +} + +bool isFileBlacklisted(const QString &fileName) +{ + return (!fileName.compare(QMLDIRFILENAME) || + !fileName.compare(CMAKEFILENAME)); +} + +} +} diff --git a/src/plugins/qmldesigner/generatecmakelists.h b/src/plugins/qmldesigner/generatecmakelists.h new file mode 100644 index 00000000000..55b0f6958d1 --- /dev/null +++ b/src/plugins/qmldesigner/generatecmakelists.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** 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 + +namespace QmlDesigner { +namespace GenerateCmakeLists { +void generateMenuEntry(); +void onGenerateCmakeLists(); +void generateMainCmake(const Utils::FilePath &rootDir); +void generateSubdirCmake(const Utils::FilePath &dir); +QString generateModuleCmake(const Utils::FilePath &dir); +QStringList processDirectory(const Utils::FilePath &dir); +QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath); +QStringList getDirectoryTreeResources(const Utils::FilePath &dir); +void createCmakeFile(const Utils::FilePath &filePath, const QString &content); +bool isFileBlacklisted(const QString &fileName); +} +} diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 77c4715f172..014c79b59d3 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -31,6 +31,7 @@ #include "designmodecontext.h" #include "openuiqmlfiledialog.h" #include "generateresource.h" +#include "generatecmakelists.h" #include "nodeinstanceview.h" #include "gestures.h" @@ -222,6 +223,8 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) GenerateResource::generateMenuEntry(); + GenerateCmakeLists::generateMenuEntry(); + const QString fontPath = Core::ICore::resourcePath( "qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf") diff --git a/src/plugins/qmldesigner/qmldesignerplugin.pri b/src/plugins/qmldesigner/qmldesignerplugin.pri index 58fb55788f3..4cf7edf4ba1 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.pri +++ b/src/plugins/qmldesigner/qmldesignerplugin.pri @@ -5,6 +5,7 @@ HEADERS += $$PWD/qmldesignerconstants.h \ $$PWD/designersettings.h \ $$PWD/editorproxy.h \ $$PWD/generateresource.h \ + $$PWD/generatecmakelists.h \ $$PWD/settingspage.h \ $$PWD/designmodecontext.h \ $$PWD/documentmanager.h \ @@ -20,6 +21,7 @@ SOURCES += $$PWD/qmldesignerplugin.cpp \ $$PWD/designersettings.cpp \ $$PWD/editorproxy.cpp \ $$PWD/generateresource.cpp \ + $$PWD/generatecmakelists.cpp \ $$PWD/settingspage.cpp \ $$PWD/designmodecontext.cpp \ $$PWD/documentmanager.cpp \ diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index a1cf95c0e8b..a3b70ec9706 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -1007,6 +1007,8 @@ Project { files: [ "generateresource.cpp", "generateresource.h", + "generatecmakelists.cpp", + "generatecmakelists.h", "designersettings.cpp", "designersettings.h", "designmodecontext.cpp", From 797bcb3007f82331c175e486d69945fcd008d6fd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 11 Oct 2021 13:23:34 +0200 Subject: [PATCH 012/117] Optimize mime type matching Don't count "*", don't search for "[" and for "?" inside m_pattern on every call to matchFileName(). Do it once, when constructing the MimeGlobPattern. Fix matching the pattern for names without any wildcard: index of question mark should be -1, not just different from 0. This shortens loading a Qt6 project by about 500 ms. Change-Id: I868fa5c024233467c8e717a8482268da8e9e4a66 Reviewed-by: hjk --- src/libs/utils/mimetypes/mimeglobpattern.cpp | 15 +++++++-------- src/libs/utils/mimetypes/mimeglobpattern_p.h | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/libs/utils/mimetypes/mimeglobpattern.cpp b/src/libs/utils/mimetypes/mimeglobpattern.cpp index 9ab335b862a..d595a17b7bc 100644 --- a/src/libs/utils/mimetypes/mimeglobpattern.cpp +++ b/src/libs/utils/mimetypes/mimeglobpattern.cpp @@ -104,12 +104,10 @@ bool MimeGlobPattern::matchFileName(const QString &inputFilename) const return false; const int len = filename.length(); - const int starCount = m_pattern.count(QLatin1Char('*')); - // Patterns like "*~", "*.extension" - if (m_pattern[0] == QLatin1Char('*') && m_pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 1) - { - if (len + 1 < pattern_len) return false; + if (m_pattern[0] == QLatin1Char('*') && m_openingSquareBracketPos == -1 && m_starCount == 1) { + if (len + 1 < pattern_len) + return false; const QChar *c1 = m_pattern.unicode() + pattern_len - 1; const QChar *c2 = filename.unicode() + len - 1; @@ -120,8 +118,9 @@ bool MimeGlobPattern::matchFileName(const QString &inputFilename) const } // Patterns like "README*" (well this is currently the only one like that...) - if (starCount == 1 && m_pattern.at(pattern_len - 1) == QLatin1Char('*')) { - if (len + 1 < pattern_len) return false; + if (m_starCount == 1 && m_pattern.at(pattern_len - 1) == QLatin1Char('*')) { + if (len + 1 < pattern_len) + return false; if (m_pattern.at(0) == QLatin1Char('*')) return filename.indexOf(QStringView(m_pattern).mid(1, pattern_len - 2)) != -1; @@ -134,7 +133,7 @@ bool MimeGlobPattern::matchFileName(const QString &inputFilename) const } // Names without any wildcards like "README" - if (m_pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 0 && m_pattern.indexOf(QLatin1Char('?'))) + if (m_openingSquareBracketPos == -1 && m_starCount == 0 && m_questionMarkPos == -1) return (m_pattern == filename); // Other (quite rare) patterns, like "*.anim[1-9j]": use slow but correct method diff --git a/src/libs/utils/mimetypes/mimeglobpattern_p.h b/src/libs/utils/mimetypes/mimeglobpattern_p.h index ecbfb02ce9d..28fa01551c4 100644 --- a/src/libs/utils/mimetypes/mimeglobpattern_p.h +++ b/src/libs/utils/mimetypes/mimeglobpattern_p.h @@ -73,12 +73,17 @@ public: static const unsigned DefaultWeight = 50; static const unsigned MinWeight = 1; - explicit MimeGlobPattern(const QString &thePattern, const QString &theMimeType, unsigned theWeight = DefaultWeight, Qt::CaseSensitivity s = Qt::CaseInsensitive) : - m_pattern(thePattern), m_mimeType(theMimeType), m_weight(theWeight), m_caseSensitivity(s) + explicit MimeGlobPattern(const QString &thePattern, const QString &theMimeType, + unsigned theWeight = DefaultWeight, + Qt::CaseSensitivity s = Qt::CaseInsensitive) : + m_pattern(s == Qt::CaseInsensitive ? thePattern.toLower() : thePattern), + m_mimeType(theMimeType), + m_weight(theWeight), + m_starCount(m_pattern.count(QLatin1Char('*'))), + m_openingSquareBracketPos(m_pattern.indexOf(QLatin1Char('['))), + m_questionMarkPos(m_pattern.indexOf(QLatin1Char('?'))), + m_caseSensitivity(s) { - if (s == Qt::CaseInsensitive) { - m_pattern = m_pattern.toLower(); - } } ~MimeGlobPattern() {} @@ -93,6 +98,9 @@ private: QString m_pattern; QString m_mimeType; int m_weight; + int m_starCount; + int m_openingSquareBracketPos; + int m_questionMarkPos; Qt::CaseSensitivity m_caseSensitivity; }; From fded7e4edd2ec3535e1335790656efebe8d7f2ca Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 7 Oct 2021 18:36:30 +0200 Subject: [PATCH 013/117] CMakePM: Add headers only on compiler groups without PCH sources The change that treats header files as projects added all sources for a certain language for every compiler group. This meant that for the target that has precompiled headers, the source files would be added multiple times. This change reverts to adding only the source files from a compiler group and the header files for a language type, but only for non PCH compiler group. Fixes: QTCREATORBUG-26383 Change-Id: Ib328e0a0331e0f373d5a5981489bc17c58b8eed6 Reviewed-by: David Schulz Reviewed-by: Christian Kandeler --- .../fileapidataextractor.cpp | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index c4f4810f34f..7200a060002 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -28,9 +28,10 @@ #include "fileapiparser.h" #include "projecttreehelper.h" -#include +#include #include +#include #include #include #include @@ -336,16 +337,6 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, int counter = 0; for (const TargetDetails &t : input.targetDetails) { QDir sourceDir(sourceDirectory.toString()); - - // Do not tread generated files and CMake precompiled headers as project files - const auto sourceFiles = Utils::filtered(t.sources, [buildDirectory](const SourceInfo &si) { - return !si.isGenerated && !isPchFile(buildDirectory, FilePath::fromString(si.path)); - }); - CppEditor::ProjectFileCategorizer - categorizer({}, transform(sourceFiles, [&sourceDir](const SourceInfo &si) { - return sourceDir.absoluteFilePath(si.path); - })); - bool needPostfix = t.compileGroups.size() > 1; int count = 1; for (const CompileInfo &ci : t.compileGroups) { @@ -387,20 +378,45 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, QStringList fragments = splitFragments(ci.fragments); + // Get all sources from the compiler group, except generated sources + QStringList sources; + for (auto idx: ci.sources) { + SourceInfo si = t.sources.at(idx); + if (si.isGenerated) + continue; + sources.push_back(sourceDir.absoluteFilePath(si.path)); + } + + // If we are not in a pch compiler group, add all the headers that are not generated + const bool hasPchSource = anyOf(sources, [buildDirectory](const QString &path) { + return isPchFile(buildDirectory, FilePath::fromString(path)); + }); + if (!hasPchSource) { + QString headerMimeType; + if (ci.language == "C") + headerMimeType = CppEditor::Constants::C_HEADER_MIMETYPE; + else if (ci.language == "CXX") + headerMimeType = CppEditor::Constants::CPP_HEADER_MIMETYPE; + + for (const SourceInfo &si : t.sources) { + if (si.isGenerated) + continue; + const auto mimeTypes = Utils::mimeTypesForFileName(si.path); + for (auto mime : mimeTypes) + if (mime.name() == headerMimeType) + sources.push_back(sourceDir.absoluteFilePath(si.path)); + } + } + + // Set project files except pch files + rpp.setFiles(Utils::filtered(sources, [buildDirectory](const QString &path) { + return !isPchFile(buildDirectory, FilePath::fromString(path)); + })); + FilePath precompiled_header = FilePath::fromString(findOrDefault(t.sources, [&ending](const SourceInfo &si) { return si.path.endsWith(ending); }).path); - - CppEditor::ProjectFiles sources; - if (ci.language == "C") - sources = categorizer.cSources(); - else if (ci.language == "CXX") - sources = categorizer.cxxSources(); - - rpp.setFiles(transform(sources, [](const CppEditor::ProjectFile &pf) { - return pf.path; - })); if (!precompiled_header.isEmpty()) { if (precompiled_header.toFileInfo().isRelative()) { const FilePath parentDir = FilePath::fromString(sourceDir.absolutePath()); From e3d9ba8f59a10692fc90ed737b84b9f3c48957c7 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 11 Oct 2021 14:58:11 +0200 Subject: [PATCH 014/117] QmlProject: Add support for supportedLanguages Task-number: QDS-5187 Change-Id: Ieb1cb90225db4093178fafe4ebe948d5967a529d Reviewed-by: Miikka Heikkinen --- .../fileformat/qmlprojectfileformat.cpp | 4 ++++ .../qmlprojectmanager/fileformat/qmlprojectitem.cpp | 6 ++++++ .../qmlprojectmanager/fileformat/qmlprojectitem.h | 4 ++++ src/plugins/qmlprojectmanager/qmlproject.cpp | 9 +++++++++ src/plugins/qmlprojectmanager/qmlproject.h | 1 + src/plugins/qmlprojectmanager/qmlprojectconstants.h | 1 + 6 files changed, 25 insertions(+) diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp index 53c76263a2f..d12aa87be75 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp @@ -99,6 +99,10 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi if (fileSelectorsProperty.isValid()) projectItem->setFileSelectors(fileSelectorsProperty.value.toStringList()); + const auto languagesProperty = rootNode->property(QLatin1String("supportedLanguages")); + if (languagesProperty.isValid()) + projectItem->setSupportedLanguages(languagesProperty.value.toStringList()); + const auto forceFreeTypeProperty = rootNode->property("forceFreeType"); if (forceFreeTypeProperty.isValid()) projectItem->setForceFreeType(forceFreeTypeProperty.value.toBool()); diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp index b7aa7ec434c..3815db6f102 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp @@ -77,6 +77,12 @@ void QmlProjectItem::setFileSelectors(const QStringList &selectors) m_fileSelectors = selectors; } +void QmlProjectItem::setSupportedLanguages(const QStringList &languages) +{ + if (m_supportedLanguages != languages) + m_supportedLanguages = languages; +} + /* Returns list of absolute paths */ QStringList QmlProjectItem::files() const { diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h index 2f0f8786ef7..b234117aa0d 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h @@ -63,6 +63,9 @@ public: QStringList fileSelectors() const { return m_fileSelectors; } void setFileSelectors(const QStringList &selectors); + QStringList supportedLanguages() const { return m_supportedLanguages; } + void setSupportedLanguages(const QStringList &languages); + QStringList files() const; bool matchesFile(const QString &filePath) const; @@ -85,6 +88,7 @@ protected: QString m_targetDirectory; QStringList m_importPaths; QStringList m_fileSelectors; + QStringList m_supportedLanguages; QString m_mainFile; Utils::EnvironmentItems m_environment; QVector m_content; // content property diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index c1b8c6dc430..76c405bfb60 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -340,6 +340,13 @@ QStringList QmlBuildSystem::customFileSelectors() const return {}; } +QStringList QmlBuildSystem::supportedLanguages() const +{ + if (m_projectItem) + return m_projectItem.data()->supportedLanguages(); + return {}; +} + void QmlBuildSystem::refreshProjectFile() { refresh(QmlBuildSystem::ProjectFile | Files); @@ -509,6 +516,8 @@ QVariant QmlBuildSystem::additionalData(Id id) const { if (id == Constants::customFileSelectorsData) return customFileSelectors(); + if (id == Constants::supportedLanguagesData) + return supportedLanguages(); if (id == Constants::customForceFreeTypeData) return forceFreeType(); if (id == Constants::customQtForMCUs) diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index 51028b0d549..f6f2b54f2d3 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -88,6 +88,7 @@ public: Utils::EnvironmentItems environment() const; QStringList customImportPaths() const; QStringList customFileSelectors() const; + QStringList supportedLanguages() const; bool forceFreeType() const; bool addFiles(const QStringList &filePaths); diff --git a/src/plugins/qmlprojectmanager/qmlprojectconstants.h b/src/plugins/qmlprojectmanager/qmlprojectconstants.h index 7a8df1f4f80..beb5cde0160 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectconstants.h +++ b/src/plugins/qmlprojectmanager/qmlprojectconstants.h @@ -32,6 +32,7 @@ namespace Constants { const char * const QMLPROJECT_MIMETYPE = QmlJSTools::Constants::QMLPROJECT_MIMETYPE; const char customFileSelectorsData[] = "CustomFileSelectorsData"; +const char supportedLanguagesData[] = "SupportedLanguagesData"; const char customForceFreeTypeData[] = "CustomForceFreeType"; const char customQtForMCUs[] = "CustomQtForMCUs"; const char customQt6Project[] = "CustomQt6Project"; From b071603175eb420b44b35df946d180dbd17419b8 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 6 Oct 2021 13:14:16 +0200 Subject: [PATCH 015/117] QmlDesigner: Sanitze QML file on save Before writing the annotations we also sanitize the QML file. This removes dangling PropertyChanges and dangling KeyFrameGroups. Those are simply noise and have no relevance. We only sanitize ui.qml files. Change-Id: If4bb993b808f9d96ab89296117e776e8e9eec2c3 Reviewed-by: Miikka Heikkinen --- .../components/integration/designdocument.cpp | 5 ++- .../designercore/include/rewriterview.h | 2 ++ .../designercore/model/rewriterview.cpp | 33 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index 9374e61776b..0b7d7fa2c92 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -634,8 +634,11 @@ void DesignDocument::setEditor(Core::IEditor *editor) connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave, this, [this](Core::IDocument *document) { if (m_textEditor && m_textEditor->document() == document) { - if (m_documentModel && m_documentModel->rewriterView()) + if (m_documentModel && m_documentModel->rewriterView()) { + if (fileName().completeSuffix() == "ui.qml") + m_documentModel->rewriterView()->sanitizeModel(); m_documentModel->rewriterView()->writeAuxiliaryData(); + } } }); diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index ac251ef064c..44e804f25df 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -177,6 +177,8 @@ public: ModelNode getNodeForCanonicalIndex(int index); + void sanitizeModel(); + signals: void modelInterfaceProjectUpdated(); diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index af066b81c23..e33c82b1245 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include #ifndef QMLDESIGNER_TEST #include @@ -57,6 +59,7 @@ #include #include +#include using namespace QmlDesigner::Internal; @@ -658,6 +661,36 @@ ModelNode RewriterView::getNodeForCanonicalIndex(int index) return m_canonicalIntModelNode.value(index); } +void RewriterView::sanitizeModel() +{ + if (inErrorState()) + return; + + QmlObjectNode root = rootModelNode(); + + QTC_ASSERT(root.isValid(), return); + + QList danglingNodes; + + const auto danglingStates = root.allInvalidStateOperations(); + const auto danglingKeyframeGroups = QmlTimelineKeyframeGroup::allInvalidTimelineKeyframeGroups(this); + + std::transform(danglingStates.begin(), + danglingStates.end(), + std::back_inserter(danglingNodes), + [](const auto &node) { return node.modelNode(); }); + + std::transform(danglingKeyframeGroups.begin(), + danglingKeyframeGroups.end(), + std::back_inserter(danglingNodes), + [](const auto &node) { return node.modelNode(); }); + + executeInTransaction("RewriterView::sanitizeModel", [&]() { + for (auto node : std::as_const(danglingNodes)) + node.destroy(); + }); +} + Internal::ModelNodePositionStorage *RewriterView::positionStorage() const { return m_positionStorage.data(); From 46a0abef2e193838fe9a7e30a937a022c9ebd5f8 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 12 Oct 2021 08:29:01 +0200 Subject: [PATCH 016/117] PE: Fix compile with Qt 5.14 Amends 05fa3b06e549140. Change-Id: I26eff2c7f096b0beb77a87486bcae8faa2c137ca Reviewed-by: Alessandro Portale --- .../jsonwizard/jsonwizardfactory.cpp | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index f61836cffa1..431cbbf7756 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -246,9 +246,18 @@ QVariant JsonWizardFactory::mergeDataValueMaps(const QVariant &valueMap, const Q { QVariantMap retVal; +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + const QVariantMap &map = defaultValueMap.toMap(); + for (auto it = map.begin(), end = map.end(); it != end; ++it) + retVal.insert(it.key(), it.value()); + + const QVariantMap &map2 = valueMap.toMap(); + for (auto it = map2.begin(), end = map2.end(); it != end; ++it) + retVal.insert(it.key(), it.value()); +#else retVal.insert(defaultValueMap.toMap()); retVal.insert(valueMap.toMap()); - +#endif return retVal; } @@ -318,16 +327,12 @@ JsonWizardFactory::Page JsonWizardFactory::parsePage(const QVariant &value, QStr QVariant defaultSubData = defaultData.value(QLatin1String(DATA_KEY)); QVariant subData; - if (specifiedSubData.isNull()) { + if (specifiedSubData.isNull()) subData = defaultSubData; - } else if (specifiedSubData.type() == QVariant::Map) { - QVariantMap subDataMap; - subDataMap.insert(defaultSubData.toMap()); - subDataMap.insert(specifiedSubData.toMap()); - subData = subDataMap; - } else if (specifiedSubData.type() == QVariant::List) { + else if (specifiedSubData.type() == QVariant::Map) + subData = mergeDataValueMaps(specifiedSubData.toMap(), defaultSubData.toMap()); + else if (specifiedSubData.type() == QVariant::List) subData = specifiedSubData; - } if (!factory->validateData(typeId, subData, errorMessage)) return p; From 786dbcb9e86104be12ceded01188f9b4095e47be Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Oct 2021 17:19:18 +0200 Subject: [PATCH 017/117] Debugger: Force English debugger output So that ptrace output can be recognized. Fixes: QTCREATORBUG-26384 Change-Id: Ibd9456963a5379c333782287754bf9aed4235dc4 Reviewed-by: Christian Stenger --- src/plugins/debugger/gdb/gdbengine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index e53ddd7cf97..c87ec179116 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3846,6 +3846,7 @@ void GdbEngine::setupEngine() gdbCommand.addArg("-n"); Environment gdbEnv = rp.debugger.environment; + gdbEnv.setupEnglishOutput(); if (rp.runAsRoot) { CommandLine wrapped("sudo", {"-A"}); wrapped.addCommandLineAsArgs(gdbCommand); From 3ccf269f81eb7d26af1962915026ae9ce4b6d5f8 Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Fri, 10 Sep 2021 18:06:26 +0200 Subject: [PATCH 018/117] QmlDesigner: Fix for Binding Editor - Makes Binding Editor modal - Fixes Binding Editors hotkeys and actions - Adds Target item, property and expected type into title Task-numbers: QDS-2819, QDS-4878 Change-Id: Ib5c5f73e6552f58828776043f9b793a24c48a1f8 Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../HelperWidgets/ExtendedFunctionLogic.qml | 1 + .../statesEditorQmlSources/StatesDelegate.qml | 2 ++ .../bindingeditor/abstracteditordialog.cpp | 9 +++-- .../bindingeditor/abstracteditordialog.h | 3 +- .../components/bindingeditor/actioneditor.cpp | 7 ++-- .../components/bindingeditor/actioneditor.h | 2 +- .../bindingeditor/bindingeditor.cpp | 36 ++++++++++++------- .../components/bindingeditor/bindingeditor.h | 7 +++- .../bindingeditor/bindingeditorwidget.cpp | 24 ++++++++----- .../connectioneditor/connectionviewwidget.cpp | 21 +++++++---- 10 files changed, 76 insertions(+), 36 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml index 748f8356140..bdefc13a977 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml @@ -164,6 +164,7 @@ Item { bindingEditor.showWidget() bindingEditor.text = backendValue.expression bindingEditor.prepareBindings() + bindingEditor.updateWindowName() } BindingEditor { diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml index 5cbefc03d1f..2deb46b2123 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml @@ -110,6 +110,7 @@ Rectangle { bindingEditor.showWidget() bindingEditor.text = delegateWhenConditionString bindingEditor.prepareBindings() + bindingEditor.updateWindowName() } } @@ -309,6 +310,7 @@ Rectangle { } stateModelNodeProperty: statesEditorModel.stateModelNode() + stateNameProperty: myRoot.delegateStateName onRejected: { hideWidget() diff --git a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp index 872a004fcc8..5b8a4934dd7 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp @@ -46,7 +46,7 @@ AbstractEditorDialog::AbstractEditorDialog(QWidget *parent, const QString &title { setWindowFlag(Qt::Tool, true); setWindowTitle(defaultTitle()); - setModal(false); + setModal(true); setupJSEditor(); setupUIComponents(); @@ -111,11 +111,10 @@ void AbstractEditorDialog::setupJSEditor() { static BindingEditorFactory f; m_editor = qobject_cast(f.createEditor()); - m_editorWidget = qobject_cast(m_editor->editorWidget()); + Q_ASSERT(m_editor); - Core::Context context = m_editor->context(); - context.prepend(BINDINGEDITOR_CONTEXT_ID); - m_editorWidget->m_context->setContext(context); + m_editorWidget = qobject_cast(m_editor->editorWidget()); + Q_ASSERT(m_editorWidget); auto qmlDesignerEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor(); diff --git a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h index ed8cdd0a136..76de79b1957 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h +++ b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h @@ -26,9 +26,10 @@ #ifndef ABSTRACTEDITORDIALOG_H #define ABSTRACTEDITORDIALOG_H -#include #include + #include +#include #include diff --git a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp index 89364c5116c..1f2a8224d33 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp @@ -286,10 +286,13 @@ void ActionEditor::prepareConnections() m_dialog->setAllConnections(connections, singletons, states); } -void ActionEditor::updateWindowName() +void ActionEditor::updateWindowName(const QString &targetName) { if (!m_dialog.isNull()) { - m_dialog->setWindowTitle(m_dialog->defaultTitle()); + if (targetName.isEmpty()) + m_dialog->setWindowTitle(m_dialog->defaultTitle()); + else + m_dialog->setWindowTitle(m_dialog->defaultTitle() + " [" + targetName + "]"); m_dialog->raise(); } } diff --git a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h index c0356e81c42..09597bc8d18 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h +++ b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h @@ -64,7 +64,7 @@ public: void prepareConnections(); - Q_INVOKABLE void updateWindowName(); + Q_INVOKABLE void updateWindowName(const QString &targetName = {}); signals: void accepted(); diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp index d28457e1f58..c1a25b04379 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp @@ -42,8 +42,6 @@ namespace QmlDesigner { -static BindingEditor *s_lastBindingEditor = nullptr; - BindingEditor::BindingEditor(QObject *) { } @@ -62,11 +60,6 @@ void BindingEditor::prepareDialog() { QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_BINDINGEDITOR_OPENED); - if (s_lastBindingEditor) - s_lastBindingEditor->hideWidget(); - - s_lastBindingEditor = this; - m_dialog = new BindingEditorDialog(Core::ICore::dialogParent()); QObject::connect(m_dialog, &AbstractEditorDialog::accepted, @@ -91,9 +84,6 @@ void BindingEditor::showWidget(int x, int y) void BindingEditor::hideWidget() { - if (s_lastBindingEditor == this) - s_lastBindingEditor = nullptr; - if (m_dialog) { m_dialog->unregisterAutoCompletion(); //we have to do it separately, otherwise we have an autocompletion action override m_dialog->close(); @@ -125,6 +115,12 @@ void BindingEditor::setBackendValue(const QVariant &backendValue) if (node.isValid()) { m_backendValueTypeName = node.metaInfo().propertyTypeName(propertyEditorValue->name()); + QString nodeId = node.id(); + if (nodeId.isEmpty()) + nodeId = node.simplifiedTypeName(); + + m_targetName = nodeId + "." + propertyEditorValue->name(); + if (m_backendValueTypeName == "alias" || m_backendValueTypeName == "unknown") if (QmlObjectNode::isValidQmlObjectNode(node)) m_backendValueTypeName = QmlObjectNode(node).instanceType(propertyEditorValue->name()); @@ -164,6 +160,12 @@ void BindingEditor::setStateModelNode(const QVariant &stateModelNode) } } +void BindingEditor::setStateName(const QString &name) +{ + m_targetName = name; + m_targetName += ".when"; +} + void BindingEditor::setModelNode(const ModelNode &modelNode) { if (modelNode.isValid()) @@ -177,6 +179,11 @@ void BindingEditor::setBackendValueTypeName(const TypeName &backendValueTypeName emit backendValueChanged(); } +void BindingEditor::setTargetName(const QString &target) +{ + m_targetName = target; +} + void BindingEditor::prepareBindings() { if (!m_modelNode.isValid() || m_backendValueTypeName.isEmpty()) @@ -279,8 +286,13 @@ void BindingEditor::prepareBindings() void BindingEditor::updateWindowName() { - if (!m_dialog.isNull() && !m_backendValueTypeName.isEmpty()) - m_dialog->setWindowTitle(m_dialog->defaultTitle() + " [" + m_backendValueTypeName + "]"); + if (!m_dialog.isNull() && !m_backendValueTypeName.isEmpty()) { + const QString targetString = " [" + + (m_targetName.isEmpty() ? QString() : (m_targetName + ": ")) + + QString::fromUtf8(m_backendValueTypeName) + "]"; + + m_dialog->setWindowTitle(m_dialog->defaultTitle() + targetString); + } } QVariant BindingEditor::backendValue() const diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h index 495462128f8..f6c5c884321 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h @@ -44,6 +44,7 @@ class BindingEditor : public QObject Q_PROPERTY(QVariant backendValueProperty READ backendValue WRITE setBackendValue NOTIFY backendValueChanged) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) Q_PROPERTY(QVariant stateModelNodeProperty READ stateModelNode WRITE setStateModelNode NOTIFY stateModelNodeChanged) + Q_PROPERTY(QString stateNameProperty WRITE setStateName) public: BindingEditor(QObject *parent = nullptr); @@ -64,11 +65,14 @@ public: void setModelNodeBackend(const QVariant &modelNodeBackend); //2. modelnode (this one also sets backend value type name to bool) + //State Name is not mandatory, but used in bindingEditor dialog name void setStateModelNode(const QVariant &stateModelNode); + void setStateName(const QString &name); - //3. modelnode + backend value type name + //3. modelnode + backend value type name + optional target name void setModelNode(const ModelNode &modelNode); void setBackendValueTypeName(const TypeName &backendValueTypeName); + void setTargetName(const QString &target); Q_INVOKABLE void prepareBindings(); Q_INVOKABLE void updateWindowName(); @@ -93,6 +97,7 @@ private: QVariant m_stateModelNode; QmlDesigner::ModelNode m_modelNode; TypeName m_backendValueTypeName; + QString m_targetName; }; } diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp index 6cd810df379..5b9c54b4d41 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp @@ -35,6 +35,10 @@ #include #include #include +#include + +#include +#include #include @@ -43,17 +47,19 @@ namespace QmlDesigner { BindingEditorWidget::BindingEditorWidget() : m_context(new Core::IContext(this)) { - m_context->setWidget(this); - Core::ICore::addContextObject(m_context); + Core::Context context(BINDINGEDITOR_CONTEXT_ID, + ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); - const Core::Context context(BINDINGEDITOR_CONTEXT_ID); + m_context->setWidget(this); + m_context->setContext(context); + Core::ICore::addContextObject(m_context); /* * We have to register our own active auto completion shortcut, because the original short cut will * use the cursor position of the original editor in the editor manager. */ - m_completionAction = new QAction(tr("Trigger Completion"), this); + Core::Command *command = Core::ActionManager::registerAction( m_completionAction, TextEditor::Constants::COMPLETE_THIS, context); command->setDefaultKeySequence(QKeySequence( @@ -84,11 +90,9 @@ bool BindingEditorWidget::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { + if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && !keyEvent->modifiers()) { emit returnKeyClicked(); return true; - } else { - return QmlJSEditor::QmlJSEditorWidget::event(event); } } return QmlJSEditor::QmlJSEditorWidget::event(event); @@ -133,8 +137,12 @@ void BindingDocument::triggerPendingUpdates() BindingEditorFactory::BindingEditorFactory() { setId(BINDINGEDITOR_CONTEXT_ID); - setDisplayName(QCoreApplication::translate("OpenWith::Editors", QmlDesigner::BINDINGEDITOR_CONTEXT_ID)); + setDisplayName(QCoreApplication::translate("OpenWith::Editors", BINDINGEDITOR_CONTEXT_ID)); setEditorActionHandlers(0); + addMimeType(BINDINGEDITOR_CONTEXT_ID); + addMimeType(QmlJSTools::Constants::QML_MIMETYPE); + addMimeType(QmlJSTools::Constants::QMLTYPES_MIMETYPE); + addMimeType(QmlJSTools::Constants::JS_MIMETYPE); setDocumentCreator([]() { return new BindingDocument; }); setEditorWidgetCreator([]() { return new BindingEditorWidget; }); diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp index 11bfebe5e73..095b8b62622 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp @@ -159,17 +159,20 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) QMenu menu(this); - menu.addAction(tr("Open Connection Editor"), [&]() { + menu.addAction(tr("Open Connection Editor"), this, [&]() { auto *connectionModel = qobject_cast(targetView->model()); const SignalHandlerProperty property = connectionModel->signalHandlerPropertyForRow(index.row()); const ModelNode node = property.parentModelNode(); + const QString targetName = index.siblingAtColumn(ConnectionModel::TargetModelNodeRow).data().toString() + + "." + property.name(); + m_connectionEditor->showWidget(); m_connectionEditor->setConnectionValue(index.data().toString()); m_connectionEditor->setModelIndex(index); m_connectionEditor->setModelNode(node); m_connectionEditor->prepareConnections(); - m_connectionEditor->updateWindowName(); + m_connectionEditor->updateWindowName(targetName); }); QMap data; @@ -179,7 +182,7 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) const auto actions = designerActionManager.actionsForTargetView( ActionInterface::TargetView::ConnectionEditor); - for (auto actionInterface : actions) { + for (const auto &actionInterface : actions) { auto *action = actionInterface->action(); action->setData(data); menu.addAction(action); @@ -198,7 +201,7 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) QMenu menu(this); - menu.addAction(tr("Open Binding Editor"), [&]() { + menu.addAction(tr("Open Binding Editor"), this, [&]() { BindingModel *bindingModel = qobject_cast(targetView->model()); const BindingProperty property = bindingModel->bindingPropertyForRow(index.row()); @@ -209,10 +212,13 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) const TypeName typeName = property.isDynamic() ? property.dynamicTypeName() : node.metaInfo().propertyTypeName(property.name()); + const QString targetName = node.displayName() + "." + property.name(); + m_bindingEditor->showWidget(); m_bindingEditor->setBindingValue(property.expression()); m_bindingEditor->setModelNode(node); m_bindingEditor->setBackendValueTypeName(typeName); + m_bindingEditor->setTargetName(targetName); m_bindingEditor->prepareBindings(); m_bindingEditor->updateWindowName(); @@ -232,7 +238,7 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) DynamicPropertiesModel *propertiesModel = qobject_cast(targetView->model()); QMenu menu(this); - menu.addAction(tr("Open Binding Editor"), [&]() { + menu.addAction(tr("Open Binding Editor"), this, [&]() { AbstractProperty abstractProperty = propertiesModel->abstractPropertyForRow(index.row()); if (!abstractProperty.isValid()) return; @@ -247,17 +253,20 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) else return; + const QString targetName = node.displayName() + "." + abstractProperty.name(); + m_dynamicEditor->showWidget(); m_dynamicEditor->setBindingValue(newExpression); m_dynamicEditor->setModelNode(node); m_dynamicEditor->setBackendValueTypeName(abstractProperty.dynamicTypeName()); + m_dynamicEditor->setTargetName(targetName); m_dynamicEditor->prepareBindings(); m_dynamicEditor->updateWindowName(); m_dynamicIndex = index; }); - menu.addAction(tr("Reset Property"), [&]() { + menu.addAction(tr("Reset Property"), this, [&]() { propertiesModel->resetProperty(propertiesModel->abstractPropertyForRow(index.row()).name()); }); From 2292e3a7a6ebc245ac76cf3ae37e7936c77ff939 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Oct 2021 15:46:11 +0200 Subject: [PATCH 019/117] ProjectExplorer: Always set a RunControl's macro expander In some cases (e.g. "Attach to running application") there is no proper RunConfiguration, so fall back to Target or Kit. Amends e78f456083a87 Change-Id: I0093d5f573fc259fd2a72bbc1aaa22dcb8adbaee Reviewed-by: David Schulz --- src/plugins/projectexplorer/runcontrol.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 4cd0665f095..9ca0e228c3c 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -349,7 +349,7 @@ public: IDevice::ConstPtr device; Utils::Id runMode; Utils::Icon icon; - const MacroExpander *macroExpander; + const MacroExpander *macroExpander = nullptr; QPointer runConfiguration; // Not owned. Avoid use. QString buildKey; QMap settingsData; @@ -389,11 +389,12 @@ void RunControl::setRunConfiguration(RunConfiguration *runConfig) d->runConfigId = runConfig->id(); d->runnable = runConfig->runnable(); d->displayName = runConfig->expandedDisplayName(); - d->macroExpander = runConfig->macroExpander(); d->buildKey = runConfig->buildKey(); d->settingsData = runConfig->aspectData(); setTarget(runConfig->target()); + + d->macroExpander = runConfig->macroExpander(); } void RunControl::setTarget(Target *target) @@ -412,6 +413,7 @@ void RunControl::setTarget(Target *target) } setKit(target->kit()); + d->macroExpander = target->macroExpander(); d->project = target->project(); } @@ -420,6 +422,7 @@ void RunControl::setKit(Kit *kit) QTC_ASSERT(kit, return); QTC_CHECK(!d->kit); d->kit = kit; + d->macroExpander = kit->macroExpander(); if (d->runnable.device) setDevice(d->runnable.device); From 9ccf355abeea9e5c4d111cc5d9965dc7802e743f Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Mon, 4 Oct 2021 13:28:06 +0300 Subject: [PATCH 020/117] Android: put "am start" extra args at the end of the arguments list Add "am start" extra arguments after all the params used by Creator's deployment process are added. This in turn help tackle two issues: 1) Allowing users to use [-n] to start a different Activity than the default one. 2) Won't fail deployment silently is a param is a non supported arg, where adb would try to start an app but the return code is 0 even if the that app is not found. Then, we don't need the warning aspect anymore because after this change, we would rely on "adb am start" to report an exception, but the app would start anyway if the case 2 above occurs. Change-Id: Ie609b748e76a068c66c8a9be1d08ccc050167ad1 Reviewed-by: hjk --- src/plugins/android/androidrunconfiguration.cpp | 9 +-------- src/plugins/android/androidrunnerworker.cpp | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index e1477c26159..b0b3c58f998 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -90,17 +90,10 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Utils::Id id) auto amStartArgsAspect = addAspect(); amStartArgsAspect->setId(Constants::ANDROID_AM_START_ARGS); amStartArgsAspect->setSettingsKey("Android.AmStartArgsKey"); - amStartArgsAspect->setLabelText(tr("Activity manager start options:")); + amStartArgsAspect->setLabelText(tr("Activity manager start arguments:")); amStartArgsAspect->setDisplayStyle(StringAspect::LineEditDisplay); amStartArgsAspect->setHistoryCompleter("Android.AmStartArgs.History"); - auto warning = addAspect(); - warning->setDisplayStyle(StringAspect::LabelDisplay); - warning->setLabelPixmap(Icons::WARNING.pixmap()); - warning->setValue(tr("If the \"am start\" options conflict, the application might not start.\n" - "%1 uses: am start -n / [-D].") - .arg(Core::Constants::IDE_DISPLAY_NAME)); - auto preStartShellCmdAspect = addAspect(); preStartShellCmdAspect->setDisplayStyle(StringAspect::TextEditDisplay); preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST); diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 83c512a46ac..759eba59e46 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -552,7 +552,6 @@ void AndroidRunnerWorker::asyncStartHelper() runAdb(entry.split(' ', Qt::SkipEmptyParts)); QStringList args({"shell", "am", "start"}); - args << m_amStartExtraArgs; args << "-n" << m_intentName; if (m_useCppDebugger) { args << "-D"; @@ -636,6 +635,7 @@ void AndroidRunnerWorker::asyncStartHelper() } } + args << m_amStartExtraArgs; if (!m_extraAppParams.isEmpty()) { QStringList appArgs = From f49fbe7f582737efbd65c737da782af8473b9224 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Mon, 4 Oct 2021 12:19:43 +0300 Subject: [PATCH 021/117] Android: set the deploy step widget to expanded by default The deploy step widget most useful aspect is the uninstall before deploy checkbox, and having it expanded by default would improve the UX a bit by avoiding one extra mouse click. Change-Id: I23ebc90daf9290d229d93dca1b9b25629902e3f2 Reviewed-by: Alessandro Portale --- src/plugins/android/androiddeployqtstep.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 8c50c7a52c2..0910f483d69 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -88,10 +88,11 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Utils::Id id) : BuildStep(parent, id) { setImmutable(true); + setUserExpanded(true); m_uninstallPreviousPackage = addAspect(); m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey); - m_uninstallPreviousPackage->setLabel(tr("Uninstall the existing app first"), + m_uninstallPreviousPackage->setLabel(tr("Uninstall the existing app before deployment"), BoolAspect::LabelPlacement::AtCheckBox); m_uninstallPreviousPackage->setValue(false); From 34b42a477229bd2e57137909fcf9724f56c20068 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 8 Oct 2021 10:31:30 +0200 Subject: [PATCH 022/117] Utils: Introduce FilePath::mapTo{Device,Global}Path Re-directing via IDevice::mapTo{Device,Global}Path Change-Id: Ica957839479967790bbd93e90eced66aa0b122a8 Reviewed-by: David Schulz --- src/libs/utils/filepath.cpp | 18 ++++++++++++++++++ src/libs/utils/filepath.h | 3 +++ src/libs/utils/fileutils.h | 2 ++ src/plugins/docker/dockerdevice.cpp | 11 +++++++++++ src/plugins/docker/dockerdevice.h | 1 + .../devicesupport/devicemanager.cpp | 12 ++++++++++++ .../projectexplorer/devicesupport/idevice.cpp | 5 +++++ .../projectexplorer/devicesupport/idevice.h | 1 + 8 files changed, 53 insertions(+) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index fd68683acee..ce6d0cc2cdd 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -819,6 +819,24 @@ FilePath FilePath::symLinkTarget() const return FilePath::fromString(info.symLinkTarget()); } +FilePath FilePath::mapToGlobalPath() const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.mapToGlobalPath, return {}); + return s_deviceHooks.mapToGlobalPath(*this); + } + return *this; +} + +QString FilePath::mapToDevicePath() const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.mapToDevicePath, return {}); + return s_deviceHooks.mapToDevicePath(*this); + } + return m_data; +} + FilePath FilePath::withExecutableSuffix() const { FilePath res = *this; diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 409421eaf58..21ef3e12438 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -161,6 +161,9 @@ public: QDir::Filters filters = QDir::NoFilter, QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags) const; + [[nodiscard]] FilePath mapToGlobalPath() const; + [[nodiscard]] QString mapToDevicePath() const; + // makes sure that capitalization of directories is canonical // on Windows and macOS. This is rarely needed. [[nodiscard]] FilePath normalizedPathName() const; diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index a92017f7709..9fd0b6c2a03 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -78,6 +78,8 @@ public: std::function renameFile; std::function &)> searchInPath; std::function symLinkTarget; + std::function mapToGlobalPath; + std::function mapToDevicePath; std::function(const FilePath &, const QStringList &, QDir::Filters, QDir::SortFlags)> dirEntries; std::function fileContents; diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 638fb91db0e..377b777d40b 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1069,6 +1069,17 @@ FilePath DockerDevice::mapToGlobalPath(const FilePath &pathOnDevice) const return result; } +QString DockerDevice::mapToDevicePath(const Utils::FilePath &globalPath) const +{ + const FilePath normalized = globalPath.normalizedPathName(); + QString path = normalized.path(); + if (normalized.startsWithDriveLetter()) { + const QChar lowerDriveLetter = path.at(0).toLower(); + path = '/' + lowerDriveLetter + path.mid(2); // strip C: + } + return path; +} + bool DockerDevice::handlesFile(const FilePath &filePath) const { return filePath.scheme() == "docker" && filePath.host() == d->m_data.imageId; diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index ded9a93b063..c4d0efe703b 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -76,6 +76,7 @@ public: ProjectExplorer::DeviceEnvironmentFetcher::Ptr environmentFetcher() const override; Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const override; + QString mapToDevicePath(const Utils::FilePath &globalPath) const override; bool handlesFile(const Utils::FilePath &filePath) const override; bool isExecutableFile(const Utils::FilePath &filePath) const override; diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index f7470cd079b..1e671e5fe31 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -484,6 +484,18 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_uniquesymLinkTarget(filePath); }; + deviceHooks.mapToGlobalPath = [](const FilePath &filePath) { + auto device = DeviceManager::deviceForPath(filePath); + QTC_ASSERT(device, return FilePath{}); + return device->mapToGlobalPath(filePath); + }; + + deviceHooks.mapToDevicePath = [](const FilePath &filePath) { + auto device = DeviceManager::deviceForPath(filePath); + QTC_ASSERT(device, return QString{}); + return device->mapToDevicePath(filePath); + }; + deviceHooks.dirEntries = [](const FilePath &filePath, const QStringList &nameFilters, QDir::Filters filters, QDir::SortFlags sort) { auto device = DeviceManager::deviceForPath(filePath); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 8c90a7fc146..f1bedcc4416 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -212,6 +212,11 @@ FilePath IDevice::mapToGlobalPath(const FilePath &pathOnDevice) const return pathOnDevice; } +QString IDevice::mapToDevicePath(const FilePath &globalPath) const +{ + return globalPath.path(); +} + bool IDevice::handlesFile(const FilePath &filePath) const { Q_UNUSED(filePath); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 873eb380bb3..56bdbb5bd28 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -237,6 +237,7 @@ public: bool isAnyUnixDevice() const; virtual Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const; + virtual QString mapToDevicePath(const Utils::FilePath &globalPath) const; virtual bool handlesFile(const Utils::FilePath &filePath) const; virtual bool isExecutableFile(const Utils::FilePath &filePath) const; From d75005fbd2271974a048f4b496379779de43d8ba Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 8 Oct 2021 11:50:07 +0200 Subject: [PATCH 023/117] Docker: Use mapToDevicePath() in startContainer() Change-Id: Iad91144413a176bee036e03192713f5bf4695dcb Reviewed-by: David Schulz --- src/plugins/docker/dockerdevice.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 377b777d40b..65e3598e605 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -833,14 +833,7 @@ void DockerDevicePrivate::startContainer() for (QString mount : qAsConst(m_data.mounts)) { if (mount.isEmpty()) continue; - // make sure to convert windows style paths to unix style paths with the file system case: - // C:/dev/src -> /c/dev/src - if (const FilePath mountPath = FilePath::fromUserInput(mount).normalizedPathName(); - mountPath.startsWithDriveLetter()) { - const QChar lowerDriveLetter = mountPath.path().at(0).toLower(); - const FilePath path = FilePath::fromUserInput(mountPath.path().mid(2)); // strip C: - mount = '/' + lowerDriveLetter + path.path(); - } + mount = q->mapToDevicePath(FilePath::fromUserInput(mount)); dockerCreate.addArgs({"-v", mount + ':' + mount}); } @@ -1071,6 +1064,8 @@ FilePath DockerDevice::mapToGlobalPath(const FilePath &pathOnDevice) const QString DockerDevice::mapToDevicePath(const Utils::FilePath &globalPath) const { + // make sure to convert windows style paths to unix style paths with the file system case: + // C:/dev/src -> /c/dev/src const FilePath normalized = globalPath.normalizedPathName(); QString path = normalized.path(); if (normalized.startsWithDriveLetter()) { From d20a0c8c03675b24b266d6c3430442fed36fc87a Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Oct 2021 13:30:14 +0200 Subject: [PATCH 024/117] QmlDesigner: Add #include Amends d1b62588c50. Change-Id: I10a6fe427087e60dd29b18488e15519a88fd77df Reviewed-by: hjk --- src/plugins/qmldesigner/generatecmakelists.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp index d7dc13fd5bd..8e96c0ec95e 100644 --- a/src/plugins/qmldesigner/generatecmakelists.cpp +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -39,6 +39,7 @@ #include #include #include +#include using namespace Utils; From 67031627830ae6b7e1ce1cdb79e9b5fe34434783 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 12 Oct 2021 14:35:00 +0200 Subject: [PATCH 025/117] Debugger: Add commandline to "Unable to determine gdb target ABI" warning Helps finding out which gdb doesn't want to tell. Change-Id: Iab374f577ee133a3bad576dd425cad5c91391f41 Reviewed-by: hjk --- src/plugins/debugger/debuggeritem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index 36e066e09a1..3a5060cbe5c 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -225,7 +225,7 @@ void DebuggerItem::reinitializeFromFile(const Environment &sysEnv, QString *erro return; } - qWarning() << "Unable to determine gdb target ABI"; + qWarning() << "Unable to determine gdb target ABI via" << proc.commandLine().toUserOutput(); //! \note If unable to determine the GDB ABI, no ABI is appended to m_abis here. return; } From 9ea3d61aaa741a775d1bc69d8b8ecb91e710f8e0 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 12 Oct 2021 13:42:19 +0200 Subject: [PATCH 026/117] VCS: update the text cursor of VcsBaseEditorWidget TextEditorWidget::slotCursorPositionChanged makes sure that the multi text cursor in the TextEditorWidget reflects all changes of the QPlainTextEdit cursor. Fixes: QTCREATORBUG-26360 Change-Id: I43d612c6f85fedbf45179898e044b516a93a3ed8 Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/vcsbaseeditor.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index d24b96dd5f8..1989b03181e 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -958,18 +958,19 @@ void VcsBaseEditorWidget::slotCursorPositionChanged() // Adapt entries combo to new position // if the cursor goes across a file line. const int newCursorLine = textCursor().blockNumber(); - if (newCursorLine == d->m_cursorLine) - return; - // Which section does it belong to? - d->m_cursorLine = newCursorLine; - const int section = sectionOfLine(d->m_cursorLine, d->m_entrySections); - if (section != -1) { - QComboBox *entriesComboBox = d->entriesComboBox(); - if (entriesComboBox->currentIndex() != section) { - QSignalBlocker blocker(entriesComboBox); - entriesComboBox->setCurrentIndex(section); + if (newCursorLine != d->m_cursorLine) { + // Which section does it belong to? + d->m_cursorLine = newCursorLine; + const int section = sectionOfLine(d->m_cursorLine, d->m_entrySections); + if (section != -1) { + QComboBox *entriesComboBox = d->entriesComboBox(); + if (entriesComboBox->currentIndex() != section) { + QSignalBlocker blocker(entriesComboBox); + entriesComboBox->setCurrentIndex(section); + } } } + TextEditorWidget::slotCursorPositionChanged(); } void VcsBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e) From 1a0c937485eda48d10f22e2037f1b950a82e77d6 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 12 Oct 2021 16:25:50 +0200 Subject: [PATCH 027/117] VCS: use context menu actions of TextEditor in VcsBaseEditor Change-Id: I1947190ad0147d15cd4e95c5dff102b795a78bfc Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/vcsbaseeditor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 1989b03181e..c2f4d4a0c9c 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -984,8 +984,10 @@ void VcsBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e) handler->fillContextMenu(menu, d->m_parameters->type); } } - if (!menu) - menu = createStandardContextMenu(); + if (!menu) { + menu = new QMenu; + appendStandardContextMenuActions(menu); + } switch (d->m_parameters->type) { case LogOutput: // log might have diff case DiffOutput: { From cb5325f6d50dae3acdc6b4a66a24488c10bd3816 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 11 Oct 2021 11:21:16 +0200 Subject: [PATCH 028/117] Core: introduce codec support check for text documents So indiviual documents can block codecs they do not support like ui or qml files. Change-Id: I65b605762c696d38be9049f0064fd68aad0193da Reviewed-by: Christian Stenger --- src/plugins/coreplugin/dialogs/codecselector.cpp | 2 ++ src/plugins/coreplugin/textdocument.cpp | 8 +++++++- src/plugins/coreplugin/textdocument.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/dialogs/codecselector.cpp b/src/plugins/coreplugin/dialogs/codecselector.cpp index a84b0fa1122..9b5786c1b42 100644 --- a/src/plugins/coreplugin/dialogs/codecselector.cpp +++ b/src/plugins/coreplugin/dialogs/codecselector.cpp @@ -87,6 +87,8 @@ CodecSelector::CodecSelector(QWidget *parent, Core::BaseTextDocument *doc) int currentIndex = -1; foreach (int mib, sortedMibs) { QTextCodec *c = QTextCodec::codecForMib(mib); + if (!doc->supportsCodec(c)) + continue; if (!buf.isEmpty()) { // slow, should use a feature from QTextCodec or QTextDecoder (but those are broken currently) diff --git a/src/plugins/coreplugin/textdocument.cpp b/src/plugins/coreplugin/textdocument.cpp index 4d6c45dadfc..448854926df 100644 --- a/src/plugins/coreplugin/textdocument.cpp +++ b/src/plugins/coreplugin/textdocument.cpp @@ -183,7 +183,13 @@ void BaseTextDocument::setCodec(const QTextCodec *codec) { if (debug) qDebug() << Q_FUNC_INFO << this << (codec ? codec->name() : QByteArray()); - d->m_format.codec = codec; + if (supportsCodec(codec)) + d->m_format.codec = codec; +} + +bool BaseTextDocument::supportsCodec(const QTextCodec *) const +{ + return true; } void BaseTextDocument::switchUtf8Bom() diff --git a/src/plugins/coreplugin/textdocument.h b/src/plugins/coreplugin/textdocument.h index 7d16b6fa811..83450b8395a 100644 --- a/src/plugins/coreplugin/textdocument.h +++ b/src/plugins/coreplugin/textdocument.h @@ -46,6 +46,7 @@ public: Utils::TextFileFormat format() const; const QTextCodec *codec() const; void setCodec(const QTextCodec *); + virtual bool supportsCodec(const QTextCodec *) const; void switchUtf8Bom(); bool supportsUtf8Bom() const; Utils::TextFileFormat::LineTerminationMode lineTerminationMode() const; From 67037b1ca87fc8a39454d6011c3d68b4a150ca86 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 11 Oct 2021 11:48:40 +0200 Subject: [PATCH 029/117] Designer: block non Utf8 codecs for FormWindowFile Fixes: QTCREATORBUG-26028 Change-Id: Ia10804fef127f6caa9f9bd50ab3ff9946499e3c6 Reviewed-by: Friedemann Kleint Reviewed-by: Qt CI Bot --- src/plugins/designer/formwindowfile.cpp | 5 +++++ src/plugins/designer/formwindowfile.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/plugins/designer/formwindowfile.cpp b/src/plugins/designer/formwindowfile.cpp index 57442568139..192a1383ebf 100644 --- a/src/plugins/designer/formwindowfile.cpp +++ b/src/plugins/designer/formwindowfile.cpp @@ -247,6 +247,11 @@ QString FormWindowFile::fallbackSaveAsFileName() const return m_suggestedName; } +bool FormWindowFile::supportsCodec(const QTextCodec *codec) const +{ + return codec == QTextCodec::codecForName("UTF-8"); +} + bool FormWindowFile::writeFile(const Utils::FilePath &filePath, QString *errorString) const { if (Designer::Constants::Internal::debug) diff --git a/src/plugins/designer/formwindowfile.h b/src/plugins/designer/formwindowfile.h index ca0ad50b3f1..845a8ce0dcb 100644 --- a/src/plugins/designer/formwindowfile.h +++ b/src/plugins/designer/formwindowfile.h @@ -58,6 +58,7 @@ public: bool isSaveAsAllowed() const override; bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override; QString fallbackSaveAsFileName() const override; + bool supportsCodec(const QTextCodec *codec) const override; // Internal void setFallbackSaveAsFileName(const QString &fileName); From 0bfbdf5e7c11e047bde6951594aed36eb60def3d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 11 Oct 2021 11:50:41 +0200 Subject: [PATCH 030/117] ScxmlEditor: block non Utf8 codecs Change-Id: I7d44dc0ddb17ab543e9e578d4480a090cc6835f1 Reviewed-by: Alessandro Portale --- src/plugins/scxmleditor/scxmleditordocument.cpp | 5 +++++ src/plugins/scxmleditor/scxmleditordocument.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/plugins/scxmleditor/scxmleditordocument.cpp b/src/plugins/scxmleditor/scxmleditordocument.cpp index 22cf8285896..2ce6669e686 100644 --- a/src/plugins/scxmleditor/scxmleditordocument.cpp +++ b/src/plugins/scxmleditor/scxmleditordocument.cpp @@ -147,6 +147,11 @@ bool ScxmlEditorDocument::reload(QString *errorString, ReloadFlag flag, ChangeTy return success; } +bool ScxmlEditorDocument::supportsCodec(const QTextCodec *codec) const +{ + return codec == QTextCodec::codecForName("UTF-8"); +} + QString ScxmlEditorDocument::designWidgetContents() const { return m_designWidget->contents(); diff --git a/src/plugins/scxmleditor/scxmleditordocument.h b/src/plugins/scxmleditor/scxmleditordocument.h index 587343a70b0..f46d03f0a21 100644 --- a/src/plugins/scxmleditor/scxmleditordocument.h +++ b/src/plugins/scxmleditor/scxmleditordocument.h @@ -57,6 +57,7 @@ public: bool isSaveAsAllowed() const override; bool isModified() const override; bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override; + bool supportsCodec(const QTextCodec *codec) const override; // Internal Common::MainWidget *designWidget() const; From f58663ce1ce1170837c7d5c780072195f357622c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Oct 2021 13:51:44 +0200 Subject: [PATCH 031/117] CMake: Use FilePath::mapToDevicePath for construction cmake line Change-Id: I178803f39b5fa7707c1e4338ff02b9de18b22858 Reviewed-by: David Schulz --- src/plugins/cmakeprojectmanager/cmakeprocess.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 64e59109ddf..d8f24b43623 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -92,10 +92,8 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & } } - const QString srcDir = parameters.sourceDirectory.path(); - const auto parser = new CMakeParser; - parser->setSourceDirectory(srcDir); + parser->setSourceDirectory(parameters.sourceDirectory.path()); m_parser.addLineParser(parser); // Always use the sourceDir: If we are triggered because the build directory is getting deleted @@ -121,7 +119,13 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & connect(process.get(), &QtcProcess::finished, this, &CMakeProcess::handleProcessFinished); - CommandLine commandLine(cmake->cmakeExecutable(), QStringList({"-S", srcDir, "-B", buildDirectory.path()}) + arguments); + const FilePath cmakeExecutable = cmake->cmakeExecutable(); + const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable); + + CommandLine commandLine(cmakeExecutable); + commandLine.addArgs({"-S", sourceDirectory.mapToDevicePath(), + "-B", buildDirectory.mapToDevicePath()}); + commandLine.addArgs(arguments); TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); From a9ef0a8af81f4822e8f6190a172747777d0b32af Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 13 Oct 2021 11:03:59 +0300 Subject: [PATCH 032/117] ClearCase: Minor cleanup Replace iteration over all documents with a faster lookup. Change-Id: Iccc20ff2e5a44eef9d0bc925e25ef5c7ebaa98e9 Reviewed-by: hjk --- src/plugins/clearcase/clearcaseplugin.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 6d0486650f8..a878f8864c1 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -1826,12 +1826,8 @@ bool ClearCasePluginPrivate::vcsOpen(const FilePath &workingDir, const QString & setStatus(absPath, FileStatus::CheckedOut); } - foreach (DocumentModel::Entry *e, DocumentModel::entries()) { - if (e->fileName().toString() == absPath) { - e->document->checkPermissions(); - break; - } - } + if (DocumentModel::Entry *e = DocumentModel::entryForFilePath(FilePath::fromString(absPath))) + e->document->checkPermissions(); return !response.error; } From 11fc62e9b1ada818eba038794de5bbeebcdc158d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Oct 2021 15:59:29 +0200 Subject: [PATCH 033/117] EditorManager: Avoid one use of FilePath::toFileInfo() Change-Id: Id6312657298d29eab2f487213d296c0d5ffe2f9a Reviewed-by: David Schulz --- src/plugins/coreplugin/editormanager/editormanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index c2b432d05a2..7944c882853 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -2110,7 +2110,7 @@ void EditorManagerPrivate::updateWindowTitleForDocument(IDocument *document, QWi if (!documentName.isEmpty()) windowTitle.append(documentName); - const QString filePath = document ? document->filePath().toFileInfo().absoluteFilePath() + const QString filePath = document ? document->filePath().absoluteFilePath().path() : QString(); const QString windowTitleAddition = d->m_titleAdditionHandler ? d->m_titleAdditionHandler(filePath) From ba7aa5ea9c58249f99264cf219090cadb4a971ef Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Oct 2021 16:40:36 +0200 Subject: [PATCH 034/117] Docker: Also add Qt Quick stuff to test image Had to tweak things a bit, and the QML part doesn't start up yet: Starting docker://e5813ba3db76/data/dev/sessions/docker-quick-cmake/docker-quick-cmake... QML debugging is enabled. Only use this in a safe environment. QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-' QQmlApplicationEngine failed to load component qrc:/main.qml:2 module "QtQuick.Window" is not installed qrc:/main.qml:1 module "QtQuick" is not installed qrc:/main.qml:2 module "QtQuick.Window" is not installed qrc:/main.qml:1 module "QtQuick" is not installed Change-Id: If7ec4aebee27880e01af6184ae22509e97054137 Reviewed-by: David Schulz --- .../docker/Dockerfile-qt-5-ubuntu-20.04-build | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/manual/docker/Dockerfile-qt-5-ubuntu-20.04-build b/tests/manual/docker/Dockerfile-qt-5-ubuntu-20.04-build index be10684ac3f..6aa5aad09ea 100644 --- a/tests/manual/docker/Dockerfile-qt-5-ubuntu-20.04-build +++ b/tests/manual/docker/Dockerfile-qt-5-ubuntu-20.04-build @@ -1,10 +1,10 @@ FROM ubuntu:20.04 -RUN apt update && \ - apt upgrade -y && \ - apt dist-upgrade -y && \ - apt install -y gpg wget software-properties-common +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get dist-upgrade -y && \ + apt-get install -y gpg wget software-properties-common RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \ | gpg --dearmor - \ @@ -12,13 +12,17 @@ RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/nul RUN apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ focal main' -RUN DEBIAN_FRONTEND=noninteractive apt-get install -y \ +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ git \ openssh-client \ sudo \ vim \ cmake \ qtbase5-dev \ + qtdeclarative5-dev \ + qtquickcontrols2-5-dev \ + qtdeclarative5-dev-tools \ libqt5core5a \ libqt5widgets5 \ libqt5quick5 \ @@ -30,5 +34,6 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get install -y \ nim \ linux-tools-common \ valgrind \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* + && apt-get clean + +# && rm -rf /var/lib/apt/lists/* From 7e9f955a589b3b92c55db70410a85192e00e5e40 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 13 Oct 2021 09:56:52 +0200 Subject: [PATCH 035/117] Docker: Use only path part of FilePath when mapping to device Otherwise neither normalizedPathName nor startsWithDriveLetter works as intended when used with a non local path, but these are required to take the correct code path in FilePath::mapToDevicePath. Change-Id: I25e8f1a6a01a3e4056633ff3afec883cfbeb0e46 Reviewed-by: hjk --- src/plugins/docker/dockerdevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 65e3598e605..eaf27690e6c 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1066,7 +1066,7 @@ QString DockerDevice::mapToDevicePath(const Utils::FilePath &globalPath) const { // make sure to convert windows style paths to unix style paths with the file system case: // C:/dev/src -> /c/dev/src - const FilePath normalized = globalPath.normalizedPathName(); + const FilePath normalized = FilePath::fromString(globalPath.path()).normalizedPathName(); QString path = normalized.path(); if (normalized.startsWithDriveLetter()) { const QChar lowerDriveLetter = path.at(0).toLower(); From 8b45f1f6c58ee605655f0254c6b037450f65b3a5 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 12 Oct 2021 16:07:19 +0200 Subject: [PATCH 036/117] QmlDesigner: Only create components as primitives if actually possible The type might not actually be exported and imported as a folder import. Change-Id: I0ada27d619727044c2f8b8a601a2632a44c5a7cb Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Bot --- .../instances/servernodeinstance.cpp | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 2aa17d9e2b7..fc5118727b4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -234,6 +234,25 @@ bool isInPathList(const QStringList &pathList, const QString &componentPath) }); } +bool canBeCreatedAsPrimitive(const QStringList &pathList, + const InstanceContainer &instanceContainer, + QQmlContext *context, + QObject *&object) +{ + if (isInPathList(pathList, instanceContainer.componentPath())) { + object = Internal::ObjectNodeInstance::createPrimitive(QString::fromUtf8( + instanceContainer.type()), + instanceContainer.majorNumber(), + instanceContainer.minorNumber(), + context); + + if (object) + return true; + + } + return false; +} + ServerNodeInstance ServerNodeInstance::create(NodeInstanceServer *nodeInstanceServer, const InstanceContainer &instanceContainer, ComponentWrap componentWrap) @@ -249,8 +268,8 @@ ServerNodeInstance ServerNodeInstance::create(NodeInstanceServer *nodeInstanceSe if (object == nullptr) nodeInstanceServer->sendDebugOutput(DebugOutputCommand::ErrorType, QLatin1String("Custom parser object could not be created."), instanceContainer.instanceId()); } else if (!instanceContainer.componentPath().isEmpty() - && !isInPathList(nodeInstanceServer->engine()->importPathList(), - instanceContainer.componentPath())) { + && !canBeCreatedAsPrimitive(nodeInstanceServer->engine()->importPathList(), + instanceContainer, nodeInstanceServer->context(), object)) { object = Internal::ObjectNodeInstance::createComponent(instanceContainer.componentPath(), nodeInstanceServer->context()); if (object == nullptr) { object = Internal::ObjectNodeInstance::createPrimitive(QString::fromUtf8(instanceContainer.type()), instanceContainer.majorNumber(), instanceContainer.minorNumber(), nodeInstanceServer->context()); @@ -260,7 +279,7 @@ ServerNodeInstance ServerNodeInstance::create(NodeInstanceServer *nodeInstanceSe nodeInstanceServer->sendDebugOutput(DebugOutputCommand::ErrorType, message + errors, instanceContainer.instanceId()); } } - } else { + } else if (!object) { object = Internal::ObjectNodeInstance::createPrimitive(QString::fromUtf8(instanceContainer.type()), instanceContainer.majorNumber(), instanceContainer.minorNumber(), nodeInstanceServer->context()); if (object == nullptr) nodeInstanceServer->sendDebugOutput(DebugOutputCommand::ErrorType, QLatin1String("Item could not be created."), instanceContainer.instanceId()); From 6e6753a0642b89a6ee5baac95dcde112be6bd951 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 13 Oct 2021 09:59:53 +0200 Subject: [PATCH 037/117] Docker: use mapped working directory for remote processes Change-Id: Ibbc89f963ca42510cf072b242a5cdfdc0d4c23ff Reviewed-by: hjk --- src/plugins/docker/dockerdevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index eaf27690e6c..4461c7a1e86 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1576,7 +1576,7 @@ void DockerDevice::runProcess(QtcProcess &process) const CommandLine cmd{"docker", {"exec"}}; if (!workingDir.isEmpty()) { - cmd.addArgs({"-w", workingDir.path()}); + cmd.addArgs({"-w", mapToDevicePath(workingDir)}); if (QTC_GUARD(workingDir.needsDevice())) // warn on local working directory for docker cmd process.setWorkingDirectory(FileUtils::homePath()); // reset working dir for docker exec } From ea8400a9ffd365300fbbb25abec8f71e9c6a016a Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 12 Oct 2021 15:17:08 +0200 Subject: [PATCH 038/117] StudioWelcome: Do not use TitilliumWeb as system font Task-number: QDS-1081 Change-Id: I6c78fc0a95163f72168a29373a8e190d4bdf3167 Reviewed-by: Thomas Hartmann --- src/plugins/studiowelcome/studiowelcomeplugin.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 52957d71925..ae5bbf29fab 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -340,11 +340,6 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro qmlRegisterType("projectmodel", 1, 0, "ProjectModel"); qmlRegisterType("usagestatistics", 1, 0, "UsageStatisticModel"); - m_welcomeMode = new WelcomeMode; - - QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf"); - QFont systemFont("Titillium Web", QApplication::font().pointSize()); - QApplication::setFont(systemFont); m_removeSplashTimer.setSingleShot(true); m_removeSplashTimer.setInterval(15000); From 38b97b404a7ed594d36103b5ea0783cf9c375c16 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 6 Oct 2021 14:55:47 +0200 Subject: [PATCH 039/117] Fix various compiler warnings Change-Id: I59db57e8501bbd0d0293ccce1b520df8acc07413 Reviewed-by: Christian Stenger --- src/plugins/android/androiddevice.cpp | 6 +++--- src/plugins/android/androidsdkmanagerwidget.cpp | 3 +-- src/plugins/clangformat/clangformatfile.cpp | 2 +- .../qmldesigner/components/formeditor/formeditorview.cpp | 1 + .../qmldesigner/designercore/metainfo/metainforeader.cpp | 3 +++ .../qmldesigner/designercore/model/qmlobjectnode.cpp | 2 +- .../designercore/model/qmltimelinekeyframegroup.cpp | 2 +- .../designercore/projectstorage/projectstoragetypes.h | 6 +++--- 8 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index bba148dda86..04d2e43281e 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -151,7 +151,7 @@ AndroidDevice::AndroidDevice() setOsType(Utils::OsTypeOtherUnix); setDeviceState(DeviceConnected); - addDeviceAction({tr("Refresh"), [](const IDevice::Ptr &device, QWidget *parent) { + addDeviceAction({tr("Refresh"), [](const IDevice::Ptr &, QWidget *) { AndroidDeviceManager::instance()->updateDevicesListOnce(); }}); @@ -614,8 +614,8 @@ AndroidDeviceManager *AndroidDeviceManager::instance() AndroidDeviceManager::AndroidDeviceManager(QObject *parent) : QObject(parent), - m_androidConfig(AndroidConfigurations::currentConfig()), - m_avdManager(m_androidConfig) + m_avdManager(m_androidConfig), + m_androidConfig(AndroidConfigurations::currentConfig()) { connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() { m_devicesUpdaterTimer.stop(); diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index c576571d32c..53a887e23d9 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -133,7 +133,6 @@ AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config, m_ui->searchField->setPlaceholderText("Filter"); connect(m_ui->searchField, &QLineEdit::textChanged, [this, proxyModel](const QString &text) { - const bool isExpanded = m_ui->expandCheck->isChecked(); proxyModel->setAcceptedSearchPackage(text); m_sdkModel->resetSelection(); // It is more convenient to expand the view with the results @@ -513,7 +512,7 @@ bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour } } - return showTopLevel || (packageState(srcIndex) & m_packageState) && packageFound(srcIndex); + return showTopLevel || ((packageState(srcIndex) & m_packageState) && packageFound(srcIndex)); } OptionsDialog::OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &args, diff --git a/src/plugins/clangformat/clangformatfile.cpp b/src/plugins/clangformat/clangformatfile.cpp index 8e532ea7976..c9955ef2a3e 100644 --- a/src/plugins/clangformat/clangformatfile.cpp +++ b/src/plugins/clangformat/clangformatfile.cpp @@ -105,7 +105,7 @@ void ClangFormatFile::saveNewFormat() // workaround: configurationAsText() add comment "# " before BasedOnStyle line const int pos = style.find("# BasedOnStyle"); - if (pos < style.size()) + if (pos < int(style.size())) style.erase(pos, 2); m_filePath.writeFileContents(QByteArray::fromStdString(style)); } diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 53c26261a08..187bc4ca17f 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -344,6 +344,7 @@ void FormEditorView::nodeReparented(const ModelNode &node, const NodeAbstractPro void FormEditorView::nodeSourceChanged(const ModelNode &node, const QString &newNodeSource) { + Q_UNUSED(newNodeSource) addOrRemoveFormEditorItem(node); } diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp index 28d8e028260..46ad1270e72 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp @@ -89,6 +89,7 @@ void MetaInfoReader::setQualifcation(const TypeName &qualification) void MetaInfoReader::elementStart(const QString &name, const QmlJS::SourceLocation &nameLocation) { + Q_UNUSED(nameLocation) switch (parserState()) { case ParsingDocument: setParserState(readDocument(name)); break; case ParsingMetaInfo: setParserState(readMetaInfoRootElement(name)); break; @@ -133,6 +134,8 @@ void MetaInfoReader::propertyDefinition(const QString &name, const QVariant &value, const QmlJS::SourceLocation &valueLocation) { + Q_UNUSED(nameLocation) + Q_UNUSED(valueLocation) switch (parserState()) { case ParsingType: readTypeProperty(name, value); break; case ParsingImports: readImportsProperty(name, value); break; diff --git a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp index 55305c72d17..2445042fbb5 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp @@ -332,7 +332,7 @@ static void removeStateOperationsForChildren(const QmlObjectNode &node) stateOperation.modelNode().destroy(); //remove of belonging StatesOperations } - for (const QmlObjectNode &childNode : node.modelNode().directSubModelNodes()) { + for (const QmlObjectNode childNode : node.modelNode().directSubModelNodes()) { removeStateOperationsForChildren(childNode); } } diff --git a/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframegroup.cpp b/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframegroup.cpp index 85eb51de448..924a4e0ee65 100644 --- a/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframegroup.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframegroup.cpp @@ -310,7 +310,7 @@ QList QmlTimelineKeyframeGroup::allInvalidTimelineKeyf QTC_ASSERT(view->rootModelNode().isValid(), return ret); const auto groups = view->rootModelNode().subModelNodesOfType("QtQuick.Timeline.KeyframeGroup"); - for (const QmlTimelineKeyframeGroup &group : groups) { + for (const QmlTimelineKeyframeGroup group : groups) { if (group.isDangling()) ret.append(group); } diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index 50db7c48537..97958d7c309 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -650,9 +650,9 @@ public: , functionDeclarations{std::move(functionDeclarations)} , signalDeclarations{std::move(signalDeclarations)} , enumerationDeclarations{std::move(enumerationDeclarations)} - , moduleId{moduleId} , accessSemantics{accessSemantics} , sourceId{sourceId} + , moduleId{moduleId} , changeLevel{changeLevel} {} @@ -663,9 +663,9 @@ public: int sourceId) : typeName{typeName} , prototype{NativeType{prototype}} - , moduleId{moduleId} , accessSemantics{static_cast(accessSemantics)} , sourceId{sourceId} + , moduleId{moduleId} {} @@ -677,10 +677,10 @@ public: int sourceId) : typeName{typeName} , prototype{NativeType{prototype}} - , moduleId{moduleId} , accessSemantics{static_cast(accessSemantics)} , sourceId{sourceId} , typeId{typeId} + , moduleId{moduleId} {} friend bool operator==(const Type &first, const Type &second) noexcept From 6dd66e012b49f634541457aafffc2367e91d95e7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 13 Oct 2021 14:41:31 +0200 Subject: [PATCH 040/117] CppEditor: Fix possible crash in CompleteSwitchCaseStatement There can be an unexpected null pointer if the built-in code model fails to parse the code properly. Fixes: QTCREATORBUG-26316 Change-Id: I5751be505b1182df17f58e1a174d645cef1e95cf Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppquickfixes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 8b9fdce1908..91974761c28 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -2483,7 +2483,7 @@ void CompleteSwitchCaseStatement::match(const CppQuickFixInterface &interface, AST *ast = path.at(depth); SwitchStatementAST *switchStatement = ast->asSwitchStatement(); if (switchStatement) { - if (!switchStatement->statement) + if (!switchStatement->statement || !switchStatement->symbol) return; CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement(); if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;" From e1a69fccb15a87ffc637898cf2248358edb01258 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 13 Oct 2021 08:32:06 +0200 Subject: [PATCH 041/117] FakeVim: Only drop full-line comments This is not what real vim does, but :help comments looks scary, we don't support more complex scripts anyway, and full-line comments at least allow some commenting. Fixes: QTCREATORBUG-26254 Change-Id: I9018d06d2a929fad6d3d301240928b6a8b109710 Reviewed-by: Lukas Holecek Reviewed-by: hjk --- src/plugins/fakevim/fakevimhandler.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index ae9cfc173f2..f0ab3becb03 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -6598,13 +6598,12 @@ bool FakeVimHandler::Private::handleExSourceCommand(const ExCommand &cmd) while (!file.atEnd() || !line.isEmpty()) { QByteArray nextline = !file.atEnd() ? file.readLine() : QByteArray(); - // remove comment - int i = nextline.lastIndexOf('"'); - if (i != -1) - nextline = nextline.remove(i, nextline.size() - i); - nextline = nextline.trimmed(); + // remove full line comment. for being precise, check :help comment in vim. + if (nextline.startsWith('"')) + continue; + // multi-line command? if (nextline.startsWith('\\')) { line += nextline.mid(1); From 78da7e2922274c429bb677abf63157b8ae679d03 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sun, 5 Sep 2021 19:44:16 +0300 Subject: [PATCH 042/117] Move sdkmanager's sdk level parsing to AndroidConfig Both the sdkmanger and avdmanager (maybe more) need to parse the sdk level for packages and devices which may contain letters, make them use the same logic. Change-Id: Iff7fef3a66e00fac11b833f73f2f334a4cf1a766 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/plugins/android/androidconfigurations.cpp | 22 ++++++++++++++++ src/plugins/android/androidconfigurations.h | 1 + src/plugins/android/androidsdkmanager.cpp | 26 ++----------------- .../android/avdmanageroutputparser.cpp | 3 ++- tests/auto/android/CMakeLists.txt | 3 +++ 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index c769a744d26..5a09199c9de 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -418,6 +418,28 @@ QString AndroidConfig::apiLevelNameFor(const SdkPlatform *platform) QString("android-%1").arg(platform->apiLevel()) : ""; } +int AndroidConfig::platformNameToApiLevel(const QString &platformName) +{ + int apiLevel = -1; + static const QRegularExpression re("(android-)(?[0-9A-Z]{1,})", + QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatch match = re.match(platformName); + if (match.hasMatch()) { + QString apiLevelStr = match.captured("apiLevel"); + bool isUInt; + apiLevel = apiLevelStr.toUInt(&isUInt); + if (!isUInt) { + if (apiLevelStr == 'Q') + apiLevel = 29; + else if (apiLevelStr == 'R') + apiLevel = 30; + else if (apiLevelStr == 'S') + apiLevel = 31; + } + } + return apiLevel; +} + bool AndroidConfig::isCmdlineSdkToolsInstalled() const { QString toolPath("cmdline-tools/latest/bin/sdkmanager"); diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 09f7ac85f1d..db65168896e 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -91,6 +91,7 @@ public: static QStringList apiLevelNamesFor(const SdkPlatformList &platforms); static QString apiLevelNameFor(const SdkPlatform *platform); + static int platformNameToApiLevel(const QString &platformName); Utils::FilePath sdkLocation() const; void setSdkLocation(const Utils::FilePath &sdkLocation); diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 943e371178a..eaa6996014a 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -69,28 +69,6 @@ Q_GLOBAL_STATIC_WITH_ARGS(QRegularExpression, assertionReg, using namespace Utils; using SdkCmdFutureInterface = QFutureInterface; -int platformNameToApiLevel(const QString &platformName) -{ - int apiLevel = -1; - QRegularExpression re("(android-)(?[0-9A-Z]{1,})", - QRegularExpression::CaseInsensitiveOption); - QRegularExpressionMatch match = re.match(platformName); - if (match.hasMatch()) { - QString apiLevelStr = match.captured("apiLevel"); - bool isUInt; - apiLevel = apiLevelStr.toUInt(&isUInt); - if (!isUInt) { - if (apiLevelStr == 'Q') - apiLevel = 29; - else if (apiLevelStr == 'R') - apiLevel = 30; - else if (apiLevelStr == 'S') - apiLevel = 31; - } - } - return apiLevel; -} - /*! Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns \c true if \a key is found, false otherwise. Result is copied into \a value. @@ -714,7 +692,7 @@ AndroidSdkPackage *SdkManagerOutputParser::parsePlatform(const QStringList &data SdkPlatform *platform = nullptr; GenericPackageData packageData; if (parseAbstractData(packageData, data, 2, "Platform")) { - int apiLevel = platformNameToApiLevel(packageData.headerParts.at(1)); + const int apiLevel = AndroidConfig::platformNameToApiLevel(packageData.headerParts.at(1)); if (apiLevel == -1) { qCDebug(sdkManagerLog) << "Platform: Cannot parse api level:"<< data; return nullptr; @@ -734,7 +712,7 @@ QPair SdkManagerOutputParser::parseSystemImage(const QString QPair result(nullptr, -1); GenericPackageData packageData; if (parseAbstractData(packageData, data, 4, "System-image")) { - int apiLevel = platformNameToApiLevel(packageData.headerParts.at(1)); + const int apiLevel = AndroidConfig::platformNameToApiLevel(packageData.headerParts.at(1)); if (apiLevel == -1) { qCDebug(sdkManagerLog) << "System-image: Cannot parse api level:"<< data; return result; diff --git a/src/plugins/android/avdmanageroutputparser.cpp b/src/plugins/android/avdmanageroutputparser.cpp index 0ca8a74e734..ac758f41c7c 100644 --- a/src/plugins/android/avdmanageroutputparser.cpp +++ b/src/plugins/android/avdmanageroutputparser.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "avdmanageroutputparser.h" +#include "androidconfigurations.h" #include #include @@ -97,7 +98,7 @@ static Utils::optional parseAvd(const QStringList &deviceInfo QSettings avdInfo(avdInfoFile.toString(), QSettings::IniFormat); value = avdInfo.value(avdInfoTargetKey).toString(); if (!value.isEmpty()) - avd.sdk = value.section('-', -1).toInt(); + avd.sdk = AndroidConfig::platformNameToApiLevel(value); else qCDebug(avdOutputParserLog) << "Avd Parsing: Cannot find sdk API:" << avdInfoFile.toString(); diff --git a/tests/auto/android/CMakeLists.txt b/tests/auto/android/CMakeLists.txt index 8f328fe98e2..bf132fe599a 100644 --- a/tests/auto/android/CMakeLists.txt +++ b/tests/auto/android/CMakeLists.txt @@ -1,5 +1,6 @@ add_qtc_test(tst_avdmanageroutputparser DEPENDS Utils + PLUGIN_DEPENDS Android INCLUDES "${PROJECT_SOURCE_DIR}/src/plugins" "${PROJECT_SOURCE_DIR}/src/plugins/android" @@ -9,6 +10,8 @@ add_qtc_test(tst_avdmanageroutputparser "${PROJECT_SOURCE_DIR}/src/plugins/android/avdmanageroutputparser.h" "${PROJECT_SOURCE_DIR}/src/plugins/android/androiddeviceinfo.cpp" "${PROJECT_SOURCE_DIR}/src/plugins/android/androiddeviceinfo.h" + "${PROJECT_SOURCE_DIR}/src/plugins/android/androidmanager.cpp" + "${PROJECT_SOURCE_DIR}/src/plugins/android/androidmanager.h" ) qtc_add_resources(tst_avdmanageroutputparser tst_avdmanageroutputparser_rcc From 3619223cbe889e005d5251a6e1606a73c2e28c31 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Mon, 13 Sep 2021 02:40:21 +0300 Subject: [PATCH 043/117] Move SDK Manager instal/uninstall checkbox to left of package name This will makes it much easier selecting packages for install/uninstall operations, and makes more space for the package name by removing the operation column, as well as making changes more apparent by marking pending changes in bold font. Change-Id: Iec86c384195dd8c51fd8f00c1de56cdbb2bab62a Reviewed-by: hjk --- .../android/androidsdkmanagerwidget.cpp | 8 ++-- src/plugins/android/androidsdkmodel.cpp | 47 ++++++++++--------- src/plugins/android/androidsdkmodel.h | 3 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index 53a887e23d9..0fe8b83d31d 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -98,12 +98,10 @@ AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config, auto proxyModel = new PackageFilterModel(m_sdkModel); m_ui->packagesView->setModel(proxyModel); + m_ui->packagesView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::packageNameColumn, - QHeaderView::ResizeToContents); - m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::apiLevelColumn, - QHeaderView::ResizeToContents); - m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::packageRevisionColumn, - QHeaderView::ResizeToContents); + QHeaderView::Stretch); + m_ui->packagesView->header()->setStretchLastSection(false); connect(m_ui->expandCheck, &QCheckBox::stateChanged, [this](int state) { if (state == Qt::Checked) m_ui->packagesView->expandAll(); diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp index 2f83e86156c..0fd6321fd00 100644 --- a/src/plugins/android/androidsdkmodel.cpp +++ b/src/plugins/android/androidsdkmodel.cpp @@ -40,7 +40,7 @@ static Q_LOGGING_CATEGORY(androidSdkModelLog, "qtc.android.sdkmodel", QtWarningM namespace Android { namespace Internal { -const int packageColCount = 4; +const int packageColCount = 3; AndroidSdkModel::AndroidSdkModel(const AndroidConfig &config, AndroidSdkManager *sdkManager, QObject *parent) @@ -74,9 +74,6 @@ QVariant AndroidSdkModel::headerData(int section, Qt::Orientation orientation, i case apiLevelColumn: data = tr("API"); break; - case operationColumn: - data = tr("Operation"); - break; default: break; } @@ -162,7 +159,6 @@ QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); - if (!index.parent().isValid()) { // Top level tools if (index.row() == 0) { @@ -202,25 +198,29 @@ QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const return p->revision().toString(); case apiLevelColumn: return apiLevelStr; - case operationColumn: - if (p->type() == AndroidSdkPackage::SdkToolsPackage && - p->state() == AndroidSdkPackage::Installed) { - return tr("Update Only"); - } else { - return p->state() == AndroidSdkPackage::Installed ? tr("Uninstall") : tr("Install"); - } default: break; } } - if (role == Qt::DecorationRole && index.column() == packageNameColumn) { - return p->state() == AndroidSdkPackage::Installed ? Utils::Icons::OK.icon() : - Utils::Icons::EMPTY16.icon(); + if (index.column() == packageNameColumn) { + if (role == Qt::CheckStateRole) { + if (p->state() == AndroidSdkPackage::Installed) + return m_changeState.contains(p) ? Qt::Unchecked : Qt::Checked; + else + return m_changeState.contains(p) ? Qt::Checked : Qt::Unchecked; + } + + if (role == Qt::FontRole) { + QFont font; + if (m_changeState.contains(p)) + font.setBold(true); + return font; + } } - if (role == Qt::CheckStateRole && index.column() == operationColumn ) - return m_changeState.contains(p) ? Qt::Checked : Qt::Unchecked; + if (role == Qt::TextAlignmentRole && index.column() == packageRevisionColumn) + return Qt::AlignHCenter; if (role == Qt::ToolTipRole) return QString("%1 - (%2)").arg(p->descriptionText()).arg(p->sdkStylePath()); @@ -245,14 +245,14 @@ QHash AndroidSdkModel::roleNames() const Qt::ItemFlags AndroidSdkModel::flags(const QModelIndex &index) const { Qt::ItemFlags f = QAbstractItemModel::flags(index); - if (index.column() == operationColumn) + if (index.column() == packageNameColumn) f |= Qt::ItemIsUserCheckable; void *ip = index.internalPointer(); - if (ip && index.column() == operationColumn) { + if (ip && index.column() == packageNameColumn) { auto package = static_cast(ip); - if (package->state() == AndroidSdkPackage::Installed && - package->type() == AndroidSdkPackage::SdkToolsPackage) { + if (package->state() == AndroidSdkPackage::Installed + && package->type() == AndroidSdkPackage::SdkToolsPackage) { f &= ~Qt::ItemIsEnabled; } } @@ -264,11 +264,14 @@ bool AndroidSdkModel::setData(const QModelIndex &index, const QVariant &value, i void *ip = index.internalPointer(); if (ip && role == Qt::CheckStateRole) { auto package = static_cast(ip); - if (value.toInt() == Qt::Checked) { + if (value.toInt() == Qt::Checked && package->state() != AndroidSdkPackage::Installed) { m_changeState << package; emit dataChanged(index, index, {Qt::CheckStateRole}); } else if (m_changeState.remove(package)) { emit dataChanged(index, index, {Qt::CheckStateRole}); + } else if (value.toInt() == Qt::Unchecked) { + m_changeState.insert(package); + emit dataChanged(index, index, {Qt::CheckStateRole}); } return true; } diff --git a/src/plugins/android/androidsdkmodel.h b/src/plugins/android/androidsdkmodel.h index af25edfbb8f..4a8d363a13f 100644 --- a/src/plugins/android/androidsdkmodel.h +++ b/src/plugins/android/androidsdkmodel.h @@ -42,8 +42,7 @@ public: enum PackageColumn { packageNameColumn = 0, apiLevelColumn, - packageRevisionColumn, - operationColumn + packageRevisionColumn }; enum ExtraRoles { From 6e4d829a409a8d2561ad0e8773ad5cd7cc64bbc1 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Tue, 21 Sep 2021 21:40:27 +0300 Subject: [PATCH 044/117] Android: handle return correct serialNumber for a running avd AVDs don't get a serial number until they are started, and avdmanager don't make it easy to get their serial either, so we need to check the running devices with adb "emu avd name" command and compare. Change-Id: I3253d25a3461a36eb9918b3c796062bf9e82e0c6 Reviewed-by: hjk --- src/plugins/android/androidconfigurations.cpp | 28 +++++++++++++++++-- src/plugins/android/androidconfigurations.h | 1 + src/plugins/android/androiddevice.cpp | 6 +++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 5a09199c9de..38396d21de0 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -712,15 +712,37 @@ QString AndroidConfig::getAvdName(const QString &serialnumber) return QString::fromLatin1(name).trimmed(); } +static SdkToolResult emulatorNameAdbCommand(const QString &serialNumber) +{ + QStringList args = AndroidDeviceInfo::adbSelector(serialNumber); + args.append({"emu", "avd", "name"}); + return AndroidManager::runAdbCommand(args); +} + +QString AndroidConfig::getRunningAvdsSerialNumber(const QString &name) const +{ + for (const AndroidDeviceInfo &dev : connectedDevices()) { + if (!dev.serialNumber.startsWith("emulator")) + continue; + SdkToolResult result = emulatorNameAdbCommand(dev.serialNumber); + const QString stdOut = result.stdOut(); + if (stdOut.isEmpty()) + continue; // Not an avd + const QStringList outputLines = stdOut.split('\n'); + if (outputLines.size() > 1 && outputLines.first() == name) + return dev.serialNumber; + } + + return {}; +} + QStringList AndroidConfig::getRunningAvdsFromDevices(const QVector &devs) { QStringList runningDevs; for (const AndroidDeviceInfo &dev : devs) { if (!dev.serialNumber.startsWith("emulator")) continue; - QStringList args = AndroidDeviceInfo::adbSelector(dev.serialNumber); - args.append({"emu", "avd", "name"}); - SdkToolResult result = AndroidManager::runAdbCommand(args); + SdkToolResult result = emulatorNameAdbCommand(dev.serialNumber); const QString stdOut = result.stdOut(); if (stdOut.isEmpty()) continue; // Not an avd diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index db65168896e..54017219032 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -174,6 +174,7 @@ public: static Utils::FilePath getJdkPath(); static QStringList getAbis(const Utils::FilePath &adbToolPath, const QString &device); + QString getRunningAvdsSerialNumber(const QString &name) const; static QStringList getRunningAvdsFromDevices(const QVector &devs); private: diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 04d2e43281e..ea4ddbf8e16 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -334,7 +334,11 @@ bool AndroidDevice::isValid() const QString AndroidDevice::serialNumber() const { - return extraData(Constants::AndroidSerialNumber).toString(); + const QString serialNumber = extraData(Constants::AndroidSerialNumber).toString(); + if (machineType() == Hardware) + return serialNumber; + + return AndroidConfigurations::currentConfig().getRunningAvdsSerialNumber(avdName()); } QString AndroidDevice::avdName() const From 336cee445e464d4e6c2cd7639ac5a434075aa73a Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Wed, 6 Oct 2021 22:24:52 +0300 Subject: [PATCH 045/117] Android: Remove unnecessary parameters in AndroidConfigurations No need to manually provide a parameter to adbToolPath inside AndroidConfigurations itself, functions that needs it can just get it directly. Change-Id: Ie319e82e4ea3b7e3ad6588284168f6116bef2686 Reviewed-by: hjk --- src/plugins/android/androidconfigurations.cpp | 29 +++++++++---------- src/plugins/android/androidconfigurations.h | 8 ++--- .../android/androidqmlpreviewworker.cpp | 4 +-- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 38396d21de0..7bc1c6310d3 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -584,16 +584,11 @@ FilePath AndroidConfig::keytoolPath() const } QVector AndroidConfig::connectedDevices(QString *error) const -{ - return connectedDevices(adbToolPath(), error); -} - -QVector AndroidConfig::connectedDevices(const FilePath &adbToolPath, QString *error) { QVector devices; QtcProcess adbProc; adbProc.setTimeoutS(30); - CommandLine cmd{adbToolPath, {"devices"}}; + CommandLine cmd{adbToolPath(), {"devices"}}; adbProc.setCommand(cmd); adbProc.runBlocking(); if (adbProc.result() != QtcProcess::FinishedWithSuccess) { @@ -619,8 +614,8 @@ QVector AndroidConfig::connectedDevices(const FilePath &adbTo AndroidDeviceInfo dev; dev.serialNumber = serialNo; dev.type = serialNo.startsWith(QLatin1String("emulator")) ? AndroidDeviceInfo::Emulator : AndroidDeviceInfo::Hardware; - dev.sdk = getSDKVersion(adbToolPath, dev.serialNumber); - dev.cpuAbi = getAbis(adbToolPath, dev.serialNumber); + dev.sdk = getSDKVersion(dev.serialNumber); + dev.cpuAbi = getAbis(dev.serialNumber); if (deviceType == QLatin1String("unauthorized")) dev.state = AndroidDeviceInfo::UnAuthorizedState; else if (deviceType == QLatin1String("offline")) @@ -655,10 +650,11 @@ bool AndroidConfig::isConnected(const QString &serialNumber) const return false; } -QString AndroidConfig::getDeviceProperty(const FilePath &adbToolPath, const QString &device, const QString &property) +QString AndroidConfig::getDeviceProperty(const QString &device, const QString &property) { // workaround for '????????????' serial numbers - CommandLine cmd(adbToolPath, AndroidDeviceInfo::adbSelector(device)); + CommandLine cmd(AndroidConfigurations::currentConfig().adbToolPath(), + AndroidDeviceInfo::adbSelector(device)); cmd.addArgs({"shell", "getprop", property}); QtcProcess adbProc; @@ -671,9 +667,9 @@ QString AndroidConfig::getDeviceProperty(const FilePath &adbToolPath, const QStr return adbProc.allOutput(); } -int AndroidConfig::getSDKVersion(const FilePath &adbToolPath, const QString &device) +int AndroidConfig::getSDKVersion(const QString &device) { - QString tmp = getDeviceProperty(adbToolPath, device, "ro.build.version.sdk"); + QString tmp = getDeviceProperty(device, "ro.build.version.sdk"); if (tmp.isEmpty()) return -1; return tmp.trimmed().toInt(); @@ -786,7 +782,7 @@ QString AndroidConfig::getProductModel(const QString &device) const if (m_serialNumberToDeviceName.contains(device)) return m_serialNumberToDeviceName.value(device); - QString model = getDeviceProperty(adbToolPath(), device, "ro.product.model").trimmed(); + QString model = getDeviceProperty(device, "ro.product.model").trimmed(); if (model.isEmpty()) return device; @@ -795,15 +791,16 @@ QString AndroidConfig::getProductModel(const QString &device) const return model; } -QStringList AndroidConfig::getAbis(const FilePath &adbToolPath, const QString &device) +QStringList AndroidConfig::getAbis(const QString &device) { + const FilePath adbTool = AndroidConfigurations::currentConfig().adbToolPath(); QStringList result; // First try via ro.product.cpu.abilist QStringList arguments = AndroidDeviceInfo::adbSelector(device); arguments << "shell" << "getprop" << "ro.product.cpu.abilist"; QtcProcess adbProc; adbProc.setTimeoutS(10); - adbProc.setCommand({adbToolPath, arguments}); + adbProc.setCommand({adbTool, arguments}); adbProc.runBlocking(); if (adbProc.result() != QtcProcess::FinishedWithSuccess) return result; @@ -826,7 +823,7 @@ QStringList AndroidConfig::getAbis(const FilePath &adbToolPath, const QString &d QtcProcess abiProc; abiProc.setTimeoutS(10); - abiProc.setCommand({adbToolPath, arguments}); + abiProc.setCommand({adbTool, arguments}); abiProc.runBlocking(); if (abiProc.result() != QtcProcess::FinishedWithSuccess) return result; diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 54017219032..2fc22ddbc2e 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -145,7 +145,6 @@ public: Utils::FilePath keytoolPath() const; QVector connectedDevices(QString *error = nullptr) const; - static QVector connectedDevices(const Utils::FilePath &adbToolPath, QString *error = nullptr); QString bestNdkPlatformMatch(int target, const QtSupport::BaseQtVersion *qtVersion) const; @@ -172,17 +171,16 @@ public: void setOpenSslLocation(const Utils::FilePath &openSslLocation); static Utils::FilePath getJdkPath(); - static QStringList getAbis(const Utils::FilePath &adbToolPath, const QString &device); + static QStringList getAbis(const QString &device); QString getRunningAvdsSerialNumber(const QString &name) const; static QStringList getRunningAvdsFromDevices(const QVector &devs); private: - static QString getDeviceProperty(const Utils::FilePath &adbToolPath, - const QString &device, const QString &property); + static QString getDeviceProperty(const QString &device, const QString &property); Utils::FilePath openJDKBinPath() const; - static int getSDKVersion(const Utils::FilePath &adbToolPath, const QString &device); + static int getSDKVersion(const QString &device); static QString getAvdName(const QString &serialnumber); void parseDependenciesJson(); diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp index 3c2adca5727..bb95616eacd 100644 --- a/src/plugins/android/androidqmlpreviewworker.cpp +++ b/src/plugins/android/androidqmlpreviewworker.cpp @@ -254,7 +254,7 @@ bool AndroidQmlPreviewWorker::ensureAvdIsRunning() appendMessage(tr("Could not start AVD."), ErrorMessageFormat); } else { m_serialNumber = devInfoLocal.serialNumber; - m_avdAbis = m_androidConfig.getAbis(m_androidConfig.adbToolPath(), m_serialNumber); + m_avdAbis = m_androidConfig.getAbis(m_serialNumber); } return !devInfoLocal.serialNumber.isEmpty(); } else { @@ -262,7 +262,7 @@ bool AndroidQmlPreviewWorker::ensureAvdIsRunning() } return false; } - m_avdAbis = m_androidConfig.getAbis(m_androidConfig.adbToolPath(), m_serialNumber); + m_avdAbis = m_androidConfig.getAbis(m_serialNumber); return true; } From d76c9bec062357c4f1c6ad38df3b30693746111e Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 13 Oct 2021 10:53:41 +0300 Subject: [PATCH 046/117] Perforce: Update document permissions after p4 edit Task-number: QTCREATORBUG-22447 Change-Id: I9d521c17409e082b66141ba607fc0256d78798b7 Reviewed-by: hjk --- src/plugins/perforce/perforceplugin.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index be00bbf30cd..16dd6739593 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1043,7 +1044,12 @@ bool PerforcePluginPrivate::vcsOpen(const FilePath &workingDir, const QString &f flags |= SilentStdOut; } const PerforceResponse result = runP4Cmd(workingDir, args, flags); - return !result.error; + if (result.error) + return false; + const FilePath absPath = workingDir.resolvePath(fileName); + if (DocumentModel::Entry *e = DocumentModel::entryForFilePath(absPath)) + e->document->checkPermissions(); + return true; } bool PerforcePluginPrivate::vcsAdd(const FilePath &workingDir, const QString &fileName) From d8a7c97fcb644a90991904dc7be1f612e2d35ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaj=20Gr=C3=B6nholm?= Date: Mon, 6 Sep 2021 14:24:23 +0300 Subject: [PATCH 047/117] Use global picking API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When gobal picking is available (Qt 6.2+), use that instead of toggling models pickable properties. Task-number: QDS-4978 Change-Id: Id2a501ae97955128874447fa8a3b8afab3d1f2c7 Reviewed-by: Tomi Korpipää Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot --- .../mockfiles/qt6/AdjustableArrow.qml | 2 ++ .../mockfiles/qt6/AreaLightHandle.qml | 1 + .../qmlpuppet/mockfiles/qt6/CameraFrustum.qml | 1 + .../mockfiles/qt6/DirectionalDraggable.qml | 1 + .../qmlpuppet/mockfiles/qt6/EditView3D.qml | 3 +- .../qmlpuppet/mockfiles/qt6/FadeHandle.qml | 1 + .../qmlpuppet/mockfiles/qt6/HelperGrid.qml | 4 +++ .../qmlpuppet/mockfiles/qt6/LightModel.qml | 1 + .../qml/qmlpuppet/mockfiles/qt6/Line3D.qml | 1 + .../mockfiles/qt6/MaterialNodeView.qml | 1 + .../qmlpuppet/mockfiles/qt6/ModelNodeView.qml | 1 + .../mockfiles/qt6/PlanarDraggable.qml | 1 + .../qmlpuppet/mockfiles/qt6/RotateGizmo.qml | 1 + .../qmlpuppet/mockfiles/qt6/RotateRing.qml | 1 + .../qmlpuppet/mockfiles/qt6/ScaleGizmo.qml | 1 + .../qml/qmlpuppet/mockfiles/qt6/ScaleRod.qml | 1 + .../qmlpuppet/mockfiles/qt6/SelectionBox.qml | 1 + .../mockfiles/qt6/SpotLightHandle.qml | 1 + .../qml2puppet/editor3d/generalhelper.cpp | 29 +++++++++++++++++++ .../qml2puppet/editor3d/generalhelper.h | 3 ++ .../qt5informationnodeinstanceserver.cpp | 4 +++ 21 files changed, 59 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/AdjustableArrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/AdjustableArrow.qml index d71b245d334..fe5d3bd5edb 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/AdjustableArrow.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/AdjustableArrow.qml @@ -31,6 +31,7 @@ DirectionalDraggable { id: arrowRoot Model { + readonly property bool _edit3dLocked: true // Make this non-pickable geometry: LineGeometry { id: lineGeometry name: "Edit 3D ScalableArrow" @@ -43,6 +44,7 @@ DirectionalDraggable { Model { id: arrowHead + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Cone" materials: [ arrowRoot.material ] y: arrowRoot.length - 3 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/AreaLightHandle.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/AreaLightHandle.qml index 78e97e81d42..c2f55bdd432 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/AreaLightHandle.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/AreaLightHandle.qml @@ -42,6 +42,7 @@ DirectionalDraggable { Model { id: handle + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Sphere" materials: [ handleRoot.material ] scale: Qt.vector3d(0.02, 0.02, 0.02) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/CameraFrustum.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/CameraFrustum.qml index adf3d53ab9b..2e53ff5d40c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/CameraFrustum.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/CameraFrustum.qml @@ -35,6 +35,7 @@ Model { property Node targetNode: null property Node scene: null property bool selected: false + readonly property bool _edit3dLocked: true // Make this non-pickable function updateGeometry() { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/DirectionalDraggable.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/DirectionalDraggable.qml index 5a2f0911dd8..2be5344521f 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/DirectionalDraggable.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/DirectionalDraggable.qml @@ -41,6 +41,7 @@ Model { property real offset: 0 readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering + readonly property bool _edit3dLocked: true // Make this non-pickable property vector3d _scenePosPressed property real _posPressed diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index ebc406c5ad7..cd3ec158a4c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -721,6 +721,7 @@ Item { Model { id: pivotCap + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Sphere" scale: pivotAutoScale.getScale(Qt.vector3d(0.03, 0.03, 0.03)) position: pivotLine.startPos @@ -760,7 +761,7 @@ Item { onPressed: (mouse)=> { if (viewRoot.editView) { - var pickResult = viewRoot.editView.pick(mouse.x, mouse.y); + var pickResult = _generalHelper.pickViewAt(viewRoot.editView, mouse.x, mouse.y); handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit), mouse.modifiers & Qt.ControlModifier); diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/FadeHandle.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/FadeHandle.qml index c50406c147f..9ad2cd18bbe 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/FadeHandle.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/FadeHandle.qml @@ -41,6 +41,7 @@ DirectionalDraggable { Model { id: handle + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Sphere" materials: [ handleRoot.material ] scale: Qt.vector3d(0.02, 0.02, 0.02) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml index b7807d8192f..10c7afd65b8 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml @@ -39,6 +39,7 @@ Node { // Note: Only one instance of HelperGrid is supported, as the geometry names are fixed Model { // Main grid lines + readonly property bool _edit3dLocked: true // Make this non-pickable geometry: GridGeometry { id: gridGeometry name: "3D Edit View Helper Grid" @@ -55,6 +56,7 @@ Node { } Model { // Subdivision lines + readonly property bool _edit3dLocked: true // Make this non-pickable geometry: GridGeometry { lines: gridGeometry.lines step: gridGeometry.step @@ -73,6 +75,7 @@ Node { } Model { // Z Axis + readonly property bool _edit3dLocked: true // Make this non-pickable geometry: GridGeometry { lines: gridGeometry.lines step: gridGeometry.step @@ -89,6 +92,7 @@ Node { ] } Model { // X Axis + readonly property bool _edit3dLocked: true // Make this non-pickable eulerRotation.z: 90 geometry: GridGeometry { lines: gridGeometry.lines diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/LightModel.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/LightModel.qml index c500f6fbb0e..f517f318d20 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/LightModel.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/LightModel.qml @@ -33,6 +33,7 @@ Model { property alias geometryName: lightGeometry.name // Name must be unique for each geometry property alias geometryType: lightGeometry.lightType property Material material + readonly property bool _edit3dLocked: true // Make this non-pickable function updateGeometry() { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/Line3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/Line3D.qml index 7e034ff75f7..f3325bfb343 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/Line3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/Line3D.qml @@ -36,6 +36,7 @@ Node { property alias color: lineMat.diffuseColor Model { + readonly property bool _edit3dLocked: true // Make this non-pickable geometry: LineGeometry { id: lineGeometry } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index 7b5e2a15b21..6103df98c2b 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -52,6 +52,7 @@ View3D { Model { id: model + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Sphere" materials: previewMaterial } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 657b0f4c944..7fe6a114163 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -82,6 +82,7 @@ View3D { Model { id: model + readonly property bool _edit3dLocked: true // Make this non-pickable eulerRotation.y: 45 source: sourceModel.source diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/PlanarDraggable.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/PlanarDraggable.qml index 1a1fea9f9ce..e66d1962a3c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/PlanarDraggable.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/PlanarDraggable.qml @@ -40,6 +40,7 @@ Model { property alias mouseArea: mouseArea readonly property bool hovering: mouseArea.hovering + readonly property bool _edit3dLocked: true // Make this non-pickable property vector3d _scenePosPressed property vector2d _planePosPressed diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateGizmo.qml index 4998974dabf..d77ebc17fb2 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateGizmo.qml @@ -189,6 +189,7 @@ Node { Model { id: freeRotator + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Sphere" materials: DefaultMaterial { id: material diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml index 385806008ee..8003839a894 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml @@ -45,6 +45,7 @@ Model { property vector3d _targetPosOnScreen property vector3d _startRotation property bool _trackBall + readonly property bool _edit3dLocked: true // Make this non-pickable signal rotateCommit() signal rotateChange() diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ScaleGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ScaleGizmo.qml index e76809f32fd..a71001689db 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ScaleGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ScaleGizmo.qml @@ -166,6 +166,7 @@ Node { Model { id: centerCube + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Cube" scale: Qt.vector3d(0.024, 0.024, 0.024) materials: DefaultMaterial { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ScaleRod.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ScaleRod.qml index 1857bfddda6..9cc5ec0e065 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ScaleRod.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ScaleRod.qml @@ -39,6 +39,7 @@ DirectionalDraggable { property vector3d _startScale Model { + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Cube" y: 10 scale: Qt.vector3d(0.020, 0.020, 0.020) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml index 1e7cc7b11ac..dd3300fd941 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml @@ -45,6 +45,7 @@ Node { Model { id: selectionBoxModel + readonly property bool _edit3dLocked: true // Make this non-pickable geometry: selectionBoxGeometry scale: selectionBox.targetNode ? selectionBox.targetNode.scale : Qt.vector3d(1, 1, 1) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SpotLightHandle.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SpotLightHandle.qml index 1c7322f4e28..314b4166ebe 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SpotLightHandle.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SpotLightHandle.qml @@ -41,6 +41,7 @@ DirectionalDraggable { Model { id: handle + readonly property bool _edit3dLocked: true // Make this non-pickable source: "#Sphere" materials: [ handleRoot.material ] scale: Qt.vector3d(0.02, 0.02, 0.02) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 02e6f2df594..d3a8b4e8f54 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -267,6 +267,31 @@ void GeneralHelper::delayedPropertySet(QObject *obj, int delay, const QString &p }); } +// Returns the first valid QQuick3DPickResult from view at (posX, PosY). +QQuick3DPickResult GeneralHelper::pickViewAt(QQuick3DViewport *view, float posX, float posY) +{ + if (!view) + return QQuick3DPickResult(); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 1) + // Make sure global picking is on + view->setGlobalPickingEnabled(true); + + // With Qt 6.2+, select first suitable result from all picked objects + auto pickResults = view->pickAll(posX, posY); + for (auto pickResult : pickResults) { + if (isPickable(pickResult.objectHit())) + return pickResult; + } +#else + // With older Qt version we'll just pick the single object + auto pickResult = view->pick(posX, posY); + if (isPickable(pickResult.objectHit())) + return pickResult; +#endif + return QQuick3DPickResult(); +} + QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode) { if (pickNode) { @@ -315,6 +340,10 @@ bool GeneralHelper::isHidden(QQuick3DNode *node) return false; } +bool GeneralHelper::isPickable(QQuick3DNode *node) { + return (node && !isLocked(node) && !isHidden(node) && node->visible()); +} + void GeneralHelper::storeToolState(const QString &sceneId, const QString &tool, const QVariant &state, int delay) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 6e888980f81..c22f310eddd 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -35,6 +35,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE class QQuick3DCamera; @@ -74,12 +75,14 @@ public: Q_INVOKABLE bool fuzzyCompare(double a, double b); Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property, const QVariant& value); + Q_INVOKABLE QQuick3DPickResult pickViewAt(QQuick3DViewport *view, float posX, float posY); Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode); Q_INVOKABLE void registerGizmoTarget(QQuick3DNode *node); Q_INVOKABLE void unregisterGizmoTarget(QQuick3DNode *node); Q_INVOKABLE bool isLocked(QQuick3DNode *node); Q_INVOKABLE bool isHidden(QQuick3DNode *node); + Q_INVOKABLE bool isPickable(QQuick3DNode *node); Q_INVOKABLE void storeToolState(const QString &sceneId, const QString &tool, const QVariant &state, int delayEmit = 0); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 19e864e6381..ee20e5636c4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -2047,8 +2047,10 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst // as changes in the node tree (reparenting, adding new nodes) can make the previously set // hide status based on ancestor unreliable. node->setProperty("_edit3dHidden", edit3dHidden); +#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1) if (auto model = qobject_cast(node)) model->setPickable(!edit3dHidden); // allow 3D objects to receive mouse clicks +#endif const auto childItems = node->childItems(); for (auto childItem : childItems) { const ServerNodeInstance quick3dInstance = getQuick3DInstanceAndHidden(childItem); @@ -2070,7 +2072,9 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst value = QVariant::fromValue(node); // Specify the actual pick target with dynamic property checkModel->setProperty("_pickTarget", value); +#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1) checkModel->setPickable(!edit3dHidden); +#endif } }; if (auto childNode = qobject_cast(childItem)) From 631b7f2815a9878434c05693792b2cfb771a6d76 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 12 Oct 2021 09:25:37 +0200 Subject: [PATCH 048/117] Editor: Fix crash when select last snippet The first variable index might not be zero. Fixes: QTCREATORBUG-26406 Change-Id: I54a9575da61d770ba82f3ddb9b1e8b0128ae51dd Reviewed-by: Christian Stenger --- src/plugins/texteditor/snippets/snippetoverlay.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/texteditor/snippets/snippetoverlay.cpp b/src/plugins/texteditor/snippets/snippetoverlay.cpp index 568470b90e4..287d0d75316 100644 --- a/src/plugins/texteditor/snippets/snippetoverlay.cpp +++ b/src/plugins/texteditor/snippets/snippetoverlay.cpp @@ -114,10 +114,10 @@ QTextCursor SnippetOverlay::nextSelectionCursor(const QTextCursor &cursor) const const SnippetSelection ¤tSelection = selectionForCursor(cursor); if (currentSelection.variableIndex >= 0) { int nextVariableIndex = currentSelection.variableIndex + 1; - if (nextVariableIndex >= m_variables.size()) { + if (!m_variables.contains(nextVariableIndex)) { if (m_finalSelectionIndex >= 0) return cursorForIndex(m_finalSelectionIndex); - nextVariableIndex = 0; + nextVariableIndex = m_variables.firstKey(); } for (int selectionIndex : m_variables[nextVariableIndex]) { @@ -142,8 +142,8 @@ QTextCursor SnippetOverlay::previousSelectionCursor(const QTextCursor &cursor) c const SnippetSelection ¤tSelection = selectionForCursor(cursor); if (currentSelection.variableIndex >= 0) { int previousVariableIndex = currentSelection.variableIndex - 1; - if (previousVariableIndex < 0) - previousVariableIndex = m_variables.size() - 1; + if (!m_variables.contains(previousVariableIndex)) + previousVariableIndex = m_variables.lastKey(); const QList &equivalents = m_variables[previousVariableIndex]; for (int i = equivalents.size() - 1; i >= 0; --i) { From b996bae04d89ae47d9e113e2f0bffdeb2949a563 Mon Sep 17 00:00:00 2001 From: Tuomo Pelkonen Date: Wed, 13 Oct 2021 15:50:23 +0300 Subject: [PATCH 049/117] QmlProject: Add support for primaryLanguage Task-number: QDS-5187 Change-Id: I05aafa726fd6c2b586d57b64239cf08c1f2342ab Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot --- .../fileformat/qmlprojectfileformat.cpp | 4 ++++ .../qmlprojectmanager/fileformat/qmlprojectitem.cpp | 6 ++++++ .../qmlprojectmanager/fileformat/qmlprojectitem.h | 4 ++++ src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp | 3 +-- src/plugins/qmlprojectmanager/qmlproject.cpp | 9 +++++++++ src/plugins/qmlprojectmanager/qmlproject.h | 1 + src/plugins/qmlprojectmanager/qmlprojectconstants.h | 1 + 7 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp index d12aa87be75..962b4034925 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp @@ -103,6 +103,10 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi if (languagesProperty.isValid()) projectItem->setSupportedLanguages(languagesProperty.value.toStringList()); + const auto primaryLanguageProperty = rootNode->property(QLatin1String("primaryLanguage")); + if (primaryLanguageProperty.isValid()) + projectItem->setPrimaryLanguage(primaryLanguageProperty.value.toString()); + const auto forceFreeTypeProperty = rootNode->property("forceFreeType"); if (forceFreeTypeProperty.isValid()) projectItem->setForceFreeType(forceFreeTypeProperty.value.toBool()); diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp index 3815db6f102..249474a224f 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp @@ -83,6 +83,12 @@ void QmlProjectItem::setSupportedLanguages(const QStringList &languages) m_supportedLanguages = languages; } +void QmlProjectItem::setPrimaryLanguage(const QString &language) +{ + if (m_primaryLanguage != language) + m_primaryLanguage = language; +} + /* Returns list of absolute paths */ QStringList QmlProjectItem::files() const { diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h index b234117aa0d..90d17e48591 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h @@ -66,6 +66,9 @@ public: QStringList supportedLanguages() const { return m_supportedLanguages; } void setSupportedLanguages(const QStringList &languages); + QString primaryLanguage() const { return m_primaryLanguage; } + void setPrimaryLanguage(const QString &language); + QStringList files() const; bool matchesFile(const QString &filePath) const; @@ -89,6 +92,7 @@ protected: QStringList m_importPaths; QStringList m_fileSelectors; QStringList m_supportedLanguages; + QString m_primaryLanguage; QString m_mainFile; Utils::EnvironmentItems m_environment; QVector m_content; // content property diff --git a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp index dc8940844b3..662e904974f 100644 --- a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp +++ b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp @@ -46,8 +46,7 @@ static bool isMultilanguagePresent() static Utils::FilePath getMultilanguageDatabaseFilePath(ProjectExplorer::Target *target) { if (target) { - auto filePath = target->project()->projectDirectory().pathAppended( - "multilanguage-experimental-v6.db"); + auto filePath = target->project()->projectDirectory().pathAppended("translations.db"); if (filePath.exists()) return filePath; } diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 76c405bfb60..876fa4e1882 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -347,6 +347,13 @@ QStringList QmlBuildSystem::supportedLanguages() const return {}; } +QString QmlBuildSystem::primaryLanguage() const +{ + if (m_projectItem) + return m_projectItem.data()->primaryLanguage(); + return {}; +} + void QmlBuildSystem::refreshProjectFile() { refresh(QmlBuildSystem::ProjectFile | Files); @@ -518,6 +525,8 @@ QVariant QmlBuildSystem::additionalData(Id id) const return customFileSelectors(); if (id == Constants::supportedLanguagesData) return supportedLanguages(); + if (id == Constants::primaryLanguageData) + return primaryLanguage(); if (id == Constants::customForceFreeTypeData) return forceFreeType(); if (id == Constants::customQtForMCUs) diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index f6f2b54f2d3..64c0cc90ecb 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -89,6 +89,7 @@ public: QStringList customImportPaths() const; QStringList customFileSelectors() const; QStringList supportedLanguages() const; + QString primaryLanguage() const; bool forceFreeType() const; bool addFiles(const QStringList &filePaths); diff --git a/src/plugins/qmlprojectmanager/qmlprojectconstants.h b/src/plugins/qmlprojectmanager/qmlprojectconstants.h index beb5cde0160..184469f2430 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectconstants.h +++ b/src/plugins/qmlprojectmanager/qmlprojectconstants.h @@ -33,6 +33,7 @@ namespace Constants { const char * const QMLPROJECT_MIMETYPE = QmlJSTools::Constants::QMLPROJECT_MIMETYPE; const char customFileSelectorsData[] = "CustomFileSelectorsData"; const char supportedLanguagesData[] = "SupportedLanguagesData"; +const char primaryLanguageData[] = "PrimaryLanguageData"; const char customForceFreeTypeData[] = "CustomForceFreeType"; const char customQtForMCUs[] = "CustomQtForMCUs"; const char customQt6Project[] = "CustomQt6Project"; From 84ee9289a0c8503f2daaf2124020980de52cdef6 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 13 Oct 2021 23:41:43 +0200 Subject: [PATCH 050/117] ProjectExplorer: Handle file names from command line as user input Change-Id: I5787e118b34d487059e9eb2f4fe6a0e05bfd3807 Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/projectexplorer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index f7fe67d213d..46db91993a0 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2602,7 +2602,7 @@ void ProjectExplorerPluginPrivate::restoreSession() dd->m_arguments = arguments; // delay opening projects from the command line even more QTimer::singleShot(0, m_instance, []() { - ICore::openFiles(Utils::transform(dd->m_arguments, &FilePath::fromString), + ICore::openFiles(Utils::transform(dd->m_arguments, &FilePath::fromUserInput), ICore::OpenFilesFlags(ICore::CanContainLineAndColumnNumbers | ICore::SwitchMode)); emit m_instance->finishedInitialization(); }); From cbf96341a1681de0898706a7c3896b69d4b6d362 Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Wed, 13 Oct 2021 16:19:17 +0200 Subject: [PATCH 051/117] QmlDesigner: Fix for BindingEditor warning Change-Id: I98fc27392e882e86221ca253ee35b2099dff8d52 Reviewed-by: Christian Kandeler Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot --- .../components/bindingeditor/bindingeditor.cpp | 13 +++++++++++++ .../components/bindingeditor/bindingeditor.h | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp index c1a25b04379..eff90366a0a 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp @@ -295,6 +295,19 @@ void BindingEditor::updateWindowName() } } +QString BindingEditor::targetName() const +{ + return m_targetName; +} + +QString BindingEditor::stateName() const +{ + if (m_targetName.endsWith(".when")) + return m_targetName.chopped(5); + + return {}; +} + QVariant BindingEditor::backendValue() const { return m_backendValue; diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h index f6c5c884321..738d9c7101d 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h @@ -44,7 +44,7 @@ class BindingEditor : public QObject Q_PROPERTY(QVariant backendValueProperty READ backendValue WRITE setBackendValue NOTIFY backendValueChanged) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) Q_PROPERTY(QVariant stateModelNodeProperty READ stateModelNode WRITE setStateModelNode NOTIFY stateModelNodeChanged) - Q_PROPERTY(QString stateNameProperty WRITE setStateName) + Q_PROPERTY(QString stateNameProperty READ stateName WRITE setStateName) public: BindingEditor(QObject *parent = nullptr); @@ -77,6 +77,9 @@ public: Q_INVOKABLE void prepareBindings(); Q_INVOKABLE void updateWindowName(); + QString targetName() const; + QString stateName() const; + signals: void accepted(); void rejected(); From 1b16eb209ce05aa6e36215a79d21931b164926d6 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 28 Sep 2021 17:05:23 +0200 Subject: [PATCH 052/117] QmlDesigner: Add QmlDocumentParser and QmlTypesParser Task-number: QDS-5174 Task-number: QDS-5228 Change-Id: I0889e8d63b0260aeb0efae1b3c8a373c18ea1f03 Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot --- .../designercore/include/projectstorageids.h | 2 +- .../projectstorage/projectstorage.h | 2 +- .../projectstorage/projectstorageexceptions.h | 6 + .../projectstorage/projectstoragetypes.h | 37 +- .../projectstorage/projectstorageupdater.cpp | 26 +- .../projectstorage/projectstorageupdater.h | 5 +- .../projectstorage/qmldocumentparser.cpp | 197 +++++++++ .../projectstorage/qmldocumentparser.h | 61 +++ .../projectstorage/qmltypesparser.cpp | 294 +++++++++++++ .../projectstorage/qmltypesparser.h | 57 ++- .../projectstorage/qmltypesparserinterface.h | 3 +- tests/unit/unittest/CMakeLists.txt | 18 +- .../unit/unittest/gtest-creator-printing.cpp | 29 +- tests/unit/unittest/gtest-creator-printing.h | 2 + .../unittest/projectstorageupdater-test.cpp | 15 +- .../unit/unittest/qmldocumentparser-test.cpp | 243 +++++++++++ tests/unit/unittest/qmltypesparser-test.cpp | 410 ++++++++++++++++++ tests/unit/unittest/qmltypesparsermock.h | 3 +- 18 files changed, 1352 insertions(+), 58 deletions(-) create mode 100644 src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp create mode 100644 src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h create mode 100644 src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp rename tests/unit/unittest/qmldom-test.cpp => src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h (57%) create mode 100644 tests/unit/unittest/qmldocumentparser-test.cpp create mode 100644 tests/unit/unittest/qmltypesparser-test.cpp diff --git a/src/plugins/qmldesigner/designercore/include/projectstorageids.h b/src/plugins/qmldesigner/designercore/include/projectstorageids.h index 76f547eeb15..765f2c9c659 100644 --- a/src/plugins/qmldesigner/designercore/include/projectstorageids.h +++ b/src/plugins/qmldesigner/designercore/include/projectstorageids.h @@ -37,7 +37,7 @@ public: constexpr explicit BasicId() = default; - BasicId(const char *) = delete; + constexpr BasicId(const char *) = delete; constexpr explicit BasicId(InternalIntergerType id) : id{id} diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 2a428c65332..9bd49ef467d 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -1096,7 +1096,7 @@ private: json.append(parameter.name); json.append("\",\"tn\":\""); json.append(parameter.typeName); - if (parameter.traits == Storage::PropertyDeclarationTraits::Non) { + if (parameter.traits == Storage::PropertyDeclarationTraits::None) { json.append("\"}"); } else { json.append("\",\"tr\":"); diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h index 0d23e116050..42790bded68 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h @@ -101,4 +101,10 @@ public: const char *what() const noexcept override { return "There is a prototype chain cycle!"; } }; +class CannotParseQmlTypesFile : std::exception +{ +public: + const char *what() const noexcept override { return "Cannot parse qml types file!"; } +}; + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index 97958d7c309..592f510c8d2 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -35,10 +35,10 @@ namespace QmlDesigner::Storage { -enum class TypeAccessSemantics : int { Invalid, Reference, Value, Sequence, IsEnum = 1 << 8 }; +enum class TypeAccessSemantics : int { None, Reference, Value, Sequence, IsEnum = 1 << 8 }; enum class PropertyDeclarationTraits : unsigned int { - Non = 0, + None = 0, IsReadOnly = 1 << 0, IsPointer = 1 << 1, IsList = 1 << 2 @@ -165,15 +165,27 @@ inline int operator<(IsQualified first, IsQualified second) return static_cast(first) < static_cast(second); } +enum class ImportKind : char { Module, Directory, QmlTypesDependency }; + class Import { public: explicit Import() = default; - explicit Import(Utils::SmallStringView name, Version version, SourceId sourceId) + explicit Import(Utils::SmallStringView name, + Version version, + SourceId sourceId, + ImportKind kind = ImportKind::Module) : name{name} , version{version} , sourceId{sourceId} + , kind{kind} + {} + + explicit Import(Version version, ModuleId moduleId, SourceId sourceId) + : version{version} + , moduleId{moduleId} + , sourceId{sourceId} {} explicit Import(Utils::SmallStringView name, int majorVersion, int minorVersion, int sourceId) @@ -185,14 +197,16 @@ public: friend bool operator==(const Import &first, const Import &second) { return first.name == second.name && first.version == second.version - && first.sourceId == second.sourceId; + && first.sourceId == second.sourceId && first.moduleId.id == second.moduleId.id; } public: - Utils::PathString name; + Utils::SmallString name; Version version; ModuleId moduleId; SourceId sourceId; + Utils::SmallString aliasName; + ImportKind kind = ImportKind::Module; }; using Imports = std::vector; @@ -269,6 +283,12 @@ public: , version{version} {} + explicit ExportedType(ModuleId moduleId, Utils::SmallStringView name, Version version = Version{}) + : name{name} + , version{version} + , moduleId{moduleId} + {} + explicit ExportedType(Utils::SmallStringView name, Version version, TypeId typeId, ModuleId moduleId) : name{name} , version{version} @@ -299,6 +319,11 @@ class ExportedTypeView { public: explicit ExportedTypeView() = default; + explicit ExportedTypeView(ModuleId moduleId, Utils::SmallStringView name, Storage::Version version) + : name{name} + , version{version} + , moduleId{moduleId} + {} explicit ExportedTypeView(int moduleId, Utils::SmallStringView name, int majorVersion, @@ -702,7 +727,7 @@ public: FunctionDeclarations functionDeclarations; SignalDeclarations signalDeclarations; EnumerationDeclarations enumerationDeclarations; - TypeAccessSemantics accessSemantics = TypeAccessSemantics::Invalid; + TypeAccessSemantics accessSemantics = TypeAccessSemantics::None; SourceId sourceId; TypeId typeId; ModuleId moduleId; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp index b5a7945181f..a16859ae230 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp @@ -73,7 +73,13 @@ void ProjectUpdater::update() SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId); - parseTypeInfos(parser.typeInfos(), directoryId, imports, types, sourceIds, fileStatuses); + parseTypeInfos(parser.typeInfos(), + directoryId, + ModuleId{&qmlDirSourceId}, + imports, + types, + sourceIds, + fileStatuses); parseQmlComponents(createComponentReferences(parser.components()), directoryId, ModuleId{&qmlDirSourceId}, @@ -85,7 +91,12 @@ void ProjectUpdater::update() } case FileState::NotChanged: { SourceIds qmltypesSourceIds = m_projectStorage.fetchSourceDependencieIds(qmlDirSourceId); - parseTypeInfos(qmltypesSourceIds, imports, types, sourceIds, fileStatuses); + parseTypeInfos(ModuleId{&qmlDirSourceId}, + qmltypesSourceIds, + imports, + types, + sourceIds, + fileStatuses); break; } case FileState::NotExists: { @@ -106,6 +117,7 @@ void ProjectUpdater::pathsWithIdsChanged(const std::vector &idPaths) {} void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, SourceContextId directoryId, + ModuleId moduleId, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, @@ -117,11 +129,12 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo}); QString qmltypesPath = directory + "/" + typeInfo; - parseTypeInfo(sourceId, qmltypesPath, imports, types, sourceIds, fileStatuses); + parseTypeInfo(sourceId, moduleId, qmltypesPath, imports, types, sourceIds, fileStatuses); } } -void ProjectUpdater::parseTypeInfos(const SourceIds &qmltypesSourceIds, +void ProjectUpdater::parseTypeInfos(ModuleId moduleId, + const SourceIds &qmltypesSourceIds, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, @@ -130,11 +143,12 @@ void ProjectUpdater::parseTypeInfos(const SourceIds &qmltypesSourceIds, for (SourceId sourceId : qmltypesSourceIds) { QString qmltypesPath = m_pathCache.sourcePath(sourceId).toQString(); - parseTypeInfo(sourceId, qmltypesPath, imports, types, sourceIds, fileStatuses); + parseTypeInfo(sourceId, moduleId, qmltypesPath, imports, types, sourceIds, fileStatuses); } } void ProjectUpdater::parseTypeInfo(SourceId sourceId, + ModuleId moduleId, const QString &qmltypesPath, Storage::Imports &imports, Storage::Types &types, @@ -144,7 +158,7 @@ void ProjectUpdater::parseTypeInfo(SourceId sourceId, if (fileState(sourceId, fileStatuses) == FileState::Changed) { sourceIds.push_back(sourceId); const auto content = m_fileSystem.contentAsQString(qmltypesPath); - m_qmlTypesParser.parse(content, imports, types, sourceIds); + m_qmlTypesParser.parse(content, imports, types, sourceId, moduleId); } } diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h index dfe8ce05c44..ce611b71412 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h @@ -88,16 +88,19 @@ private: void parseTypeInfos(const QStringList &typeInfos, SourceContextId directoryId, + ModuleId moduleId, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, FileStatuses &fileStatuses); - void parseTypeInfos(const SourceIds &qmltypesSourceIds, + void parseTypeInfos(ModuleId moduleId, + const SourceIds &qmltypesSourceIds, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, FileStatuses &fileStatuses); void parseTypeInfo(SourceId sourceId, + ModuleId moduleId, const QString &qmltypesPath, Storage::Imports &imports, Storage::Types &types, diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp new file mode 100644 index 00000000000..be0474e77f9 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 "qmldocumentparser.h" + +#include "projectstorage.h" +#include "sourcepathcache.h" + +#include + +#include + +#include + +namespace QmlDesigner { + +namespace QmlDom = QQmlJS::Dom; + +namespace { + +int convertVersionNumber(qint32 versionNumber) +{ + return versionNumber < 0 ? -1 : versionNumber; +} + +Storage::Version convertVersion(QmlDom::Version version) +{ + return Storage::Version{convertVersionNumber(version.majorVersion), + convertVersionNumber(version.minorVersion)}; +} + +Utils::PathString convertUri(const QString &uri) +{ + Utils::PathString path{QStringView{uri.begin() + 7, uri.end()}}; + if (path.endsWith("/.")) + return path; + if (path.endsWith("/")) { + path += "."; + return path; + } + + path += "/."; + return path; +} + +void addImports(Storage::Imports &imports, + const QList &qmlImports, + SourceId sourceId, + SourceContextId sourceContextId, + QmlDocumentParser::PathCache &pathCache) +{ + for (const QmlDom::Import &qmlImport : qmlImports) { + if (qmlImport.uri == u"file://.") { + SourceId directorySourceId = pathCache.sourceId(sourceContextId, "."); + imports.emplace_back(Storage::Version{}, ModuleId{&directorySourceId}, sourceId); + } else if (qmlImport.uri.startsWith(u"file://")) { + SourceId uriSourceId = pathCache.sourceId(sourceContextId, convertUri(qmlImport.uri)); + imports.emplace_back(Storage::Version{}, ModuleId{&uriSourceId}, sourceId); + } else { + imports.emplace_back(Utils::SmallString{qmlImport.uri}, + convertVersion(qmlImport.version), + sourceId); + } + } +} + +void addPropertyDeclarations(Storage::Type &type, const QmlDom::QmlObject &rootObject) +{ + for (const QmlDom::PropertyDefinition &propertyDeclaration : rootObject.propertyDefs()) { + type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name}, + Storage::ImportedType{ + Utils::SmallString{propertyDeclaration.typeName}}, + Storage::PropertyDeclarationTraits::None); + } +} + +void addParameterDeclaration(Storage::ParameterDeclarations ¶meterDeclarations, + const QList ¶meters) +{ + for (const QmlDom::MethodParameter ¶meter : parameters) { + parameterDeclarations.emplace_back(Utils::SmallString{parameter.name}, + Utils::SmallString{parameter.typeName}); + } +} + +void addFunctionAndSignalDeclarations(Storage::Type &type, const QmlDom::QmlObject &rootObject) +{ + for (const QmlDom::MethodInfo &methodInfo : rootObject.methods()) { + if (methodInfo.methodType == QmlDom::MethodInfo::Method) { + auto &functionDeclaration = type.functionDeclarations.emplace_back( + Utils::SmallString{methodInfo.name}, "", Storage::ParameterDeclarations{}); + addParameterDeclaration(functionDeclaration.parameters, methodInfo.parameters); + } else { + auto &signalDeclaration = type.signalDeclarations.emplace_back( + Utils::SmallString{methodInfo.name}); + addParameterDeclaration(signalDeclaration.parameters, methodInfo.parameters); + } + } +} + +Storage::EnumeratorDeclarations createEnumerators(const QmlDom::EnumDecl &enumeration) +{ + Storage::EnumeratorDeclarations enumeratorDeclarations; + for (const QmlDom::EnumItem &enumerator : enumeration.values()) { + enumeratorDeclarations.emplace_back(Utils::SmallString{enumerator.name()}, + static_cast(enumerator.value())); + } + return enumeratorDeclarations; +} + +void addEnumeraton(Storage::Type &type, const QmlDom::Component &component) +{ + for (const QmlDom::EnumDecl &enumeration : component.enumerations()) { + Storage::EnumeratorDeclarations enumeratorDeclarations = createEnumerators(enumeration); + type.enumerationDeclarations.emplace_back(Utils::SmallString{enumeration.name()}, + std::move(enumeratorDeclarations)); + } +} + +} // namespace + +Storage::Type QmlDocumentParser::parse(const QString &sourceContent, + Storage::Imports &imports, + SourceId sourceId, + SourceContextId sourceContextId) +{ + Storage::Type type; + + QmlDom::DomItem environment = QmlDom::DomEnvironment::create( + {}, + QmlDom::DomEnvironment::Option::SingleThreaded + | QmlDom::DomEnvironment::Option::NoDependencies); + + QmlDom::DomItem items; + + environment.loadFile( + {}, + {}, + sourceContent, + QDateTime{}, + [&](QmlDom::Path, const QmlDom::DomItem &, const QmlDom::DomItem &newItems) { + items = newItems; + }, + QmlDom::LoadOption::DefaultLoad, + QmlDom::DomType::QmlFile); + + environment.loadPendingDependencies(); + + QmlDom::DomItem file = items.field(QmlDom::Fields::currentItem); + const QmlDom::QmlFile *qmlFile = file.as(); + const auto &components = qmlFile->components(); + + if (components.empty()) + return type; + + const auto &component = components.first(); + const auto &objects = component.objects(); + + if (objects.empty()) + return type; + + const QmlDom::QmlObject &qmlObject = objects.front(); + + type.prototype = Storage::ImportedType{Utils::SmallString{qmlObject.name()}}; + + addImports(imports, qmlFile->imports(), sourceId, sourceContextId, m_pathCache); + + addPropertyDeclarations(type, qmlObject); + addFunctionAndSignalDeclarations(type, qmlObject); + addEnumeraton(type, component); + + return type; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h new file mode 100644 index 00000000000..cc272dd4227 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 "nonlockingmutex.h" +#include "qmldocumentparserinterface.h" + +namespace Sqlite { +class Database; +} + +namespace QmlDesigner { + +template +class ProjectStorage; + +template +class SourcePathCache; + +class QmlDocumentParser +{ +public: + using PathCache = QmlDesigner::SourcePathCache, + NonLockingMutex>; + + QmlDocumentParser(PathCache &pathCache) + : m_pathCache{pathCache} + {} + + virtual Storage::Type parse(const QString &sourceContent, + Storage::Imports &imports, + SourceId sourceId, + SourceContextId sourceContextId); + +private: + PathCache &m_pathCache; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp new file mode 100644 index 00000000000..ed9352cd474 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 "qmltypesparser.h" + +#include "projectstorage.h" +#include "sourcepathcache.h" + +#include + +#include +#include + +#include + +#include +#include + +namespace QmlDesigner { + +namespace QmlDom = QQmlJS::Dom; + +namespace { +void addType(const QQmlJSScope::Ptr &object, Storage::Types &types) {} + +Storage::Import createImport(const QString &dependency, SourceId sourceId) +{ + Storage::Import import; + import.kind = Storage::ImportKind::QmlTypesDependency; + import.sourceId = sourceId; + auto spaceFound = std::find_if(dependency.begin(), dependency.end(), [](QChar c) { + return c.isSpace(); + }); + import.name = Utils::SmallString{QStringView(dependency.begin(), spaceFound)}; + + auto majorVersionFound = std::find_if(spaceFound, dependency.end(), [](QChar c) { + return c.isDigit(); + }); + auto majorVersionEnd = std::find_if(majorVersionFound, dependency.end(), [](QChar c) { + return !c.isDigit(); + }); + QStringView majorVersionString(majorVersionFound, majorVersionEnd); + if (majorVersionString.isEmpty()) + return import; + import.version.major.value = majorVersionString.toInt(); + + auto minorVersionFound = std::find_if(majorVersionEnd, dependency.end(), [](QChar c) { + return c.isDigit(); + }); + auto minorVersionEnd = std::find_if(minorVersionFound, dependency.end(), [](QChar c) { + return !c.isDigit(); + }); + QStringView minorVersionString(minorVersionFound, minorVersionEnd); + if (minorVersionString.isEmpty()) + return import; + import.version.minor.value = QStringView(minorVersionFound, minorVersionEnd).toInt(); + + return import; +} + +void addImports(Storage::Imports &imports, SourceId sourceId, const QStringList &dependencies) +{ + for (const QString &dependency : dependencies) { + imports.push_back(createImport(dependency, sourceId)); + } + + imports.emplace_back("QML", Storage::Version{}, sourceId, Storage::ImportKind::QmlTypesDependency); + imports.emplace_back("QtQml", Storage::Version{}, sourceId, Storage::ImportKind::QmlTypesDependency); +} + +Storage::TypeAccessSemantics createTypeAccessSemantics(QQmlJSScope::AccessSemantics accessSematics) +{ + switch (accessSematics) { + case QQmlJSScope::AccessSemantics::Reference: + return Storage::TypeAccessSemantics::Reference; + case QQmlJSScope::AccessSemantics::Value: + return Storage::TypeAccessSemantics::Value; + case QQmlJSScope::AccessSemantics::None: + return Storage::TypeAccessSemantics::None; + case QQmlJSScope::AccessSemantics::Sequence: + return Storage::TypeAccessSemantics::Sequence; + } + + return Storage::TypeAccessSemantics::None; +} + +Storage::Version createVersion(QTypeRevision qmlVersion) +{ + return Storage::Version{qmlVersion.majorVersion(), qmlVersion.minorVersion()}; +} + +Storage::ExportedTypes createExports(ModuleId moduleId, const QList &qmlExports) +{ + Storage::ExportedTypes exportedTypes; + exportedTypes.reserve(Utils::usize(qmlExports)); + + for (const QQmlJSScope::Export &qmlExport : qmlExports) { + exportedTypes.emplace_back(moduleId, + Utils::SmallString{qmlExport.type()}, + createVersion(qmlExport.version())); + } + + return exportedTypes; +} + +Storage::PropertyDeclarationTraits createPropertyDeclarationTraits(const QQmlJSMetaProperty &qmlProperty) +{ + Storage::PropertyDeclarationTraits traits{}; + + if (qmlProperty.isList()) + traits = traits | Storage::PropertyDeclarationTraits::IsList; + + if (qmlProperty.isPointer()) + traits = traits | Storage::PropertyDeclarationTraits::IsPointer; + + if (!qmlProperty.isWritable()) + traits = traits | Storage::PropertyDeclarationTraits::IsReadOnly; + + return traits; +} + +Storage::PropertyDeclarations createProperties(const QHash &qmlProperties) +{ + Storage::PropertyDeclarations propertyDeclarations; + propertyDeclarations.reserve(Utils::usize(qmlProperties)); + + for (const QQmlJSMetaProperty &qmlProperty : qmlProperties) { + propertyDeclarations.emplace_back(Utils::SmallString{qmlProperty.propertyName()}, + Storage::NativeType{ + Utils::SmallString{qmlProperty.typeName()}}, + createPropertyDeclarationTraits(qmlProperty)); + } + + return propertyDeclarations; +} + +Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMethod) +{ + Storage::ParameterDeclarations parameterDeclarations; + + const QStringList ¶meterNames = qmlMethod.parameterNames(); + const QStringList ¶meterTypeNames = qmlMethod.parameterTypeNames(); + auto currentName = parameterNames.begin(); + auto currentType = parameterTypeNames.begin(); + auto nameEnd = parameterNames.end(); + auto typeEnd = parameterTypeNames.end(); + + for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) { + parameterDeclarations.emplace_back(Utils::SmallString{*currentName}, + Utils::SmallString{*currentType}); + } + + return parameterDeclarations; +} + +std::tuple createFunctionAndSignals( + const QMultiHash &qmlMethods) +{ + std::tuple functionAndSignalDeclarations; + Storage::FunctionDeclarations &functionsDeclarations{std::get<0>(functionAndSignalDeclarations)}; + functionsDeclarations.reserve(Utils::usize(qmlMethods)); + Storage::SignalDeclarations &signalDeclarations{std::get<1>(functionAndSignalDeclarations)}; + signalDeclarations.reserve(Utils::usize(qmlMethods)); + + for (const QQmlJSMetaMethod &qmlMethod : qmlMethods) { + if (qmlMethod.methodType() != QQmlJSMetaMethod::Type::Signal) { + functionsDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()}, + Utils::SmallString{qmlMethod.returnTypeName()}, + createParameters(qmlMethod)); + } else { + signalDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()}, + createParameters(qmlMethod)); + } + } + + return functionAndSignalDeclarations; +} + +Storage::EnumeratorDeclarations createEnumeratorsWithValues(const QQmlJSMetaEnum &qmlEnumeration) +{ + Storage::EnumeratorDeclarations enumeratorDeclarations; + + const QStringList &keys = qmlEnumeration.keys(); + const QList &values = qmlEnumeration.values(); + auto currentKey = keys.begin(); + auto currentValue = values.begin(); + auto keyEnd = keys.end(); + auto valueEnd = values.end(); + + for (; currentKey != keyEnd && currentValue != valueEnd; ++currentKey, ++currentValue) + enumeratorDeclarations.emplace_back(Utils::SmallString{*currentKey}, *currentValue); + + return enumeratorDeclarations; +} + +Storage::EnumeratorDeclarations createEnumeratorsWithoutValues(const QQmlJSMetaEnum &qmlEnumeration) +{ + Storage::EnumeratorDeclarations enumeratorDeclarations; + + for (const QString &key : qmlEnumeration.keys()) + enumeratorDeclarations.emplace_back(Utils::SmallString{key}); + + return enumeratorDeclarations; +} + +Storage::EnumeratorDeclarations createEnumerators(const QQmlJSMetaEnum &qmlEnumeration) +{ + if (qmlEnumeration.hasValues()) + return createEnumeratorsWithValues(qmlEnumeration); + + return createEnumeratorsWithoutValues(qmlEnumeration); +} + +Storage::EnumerationDeclarations createEnumeration(const QHash &qmlEnumerations) +{ + Storage::EnumerationDeclarations enumerationDeclarations; + enumerationDeclarations.reserve(Utils::usize(qmlEnumerations)); + + for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) { + enumerationDeclarations.emplace_back(Utils::SmallString{qmlEnumeration.name()}, + createEnumerators(qmlEnumeration)); + } + + return enumerationDeclarations; +} + +void addType(Storage::Types &types, SourceId sourceId, ModuleId moduleId, const QQmlJSScope &component) +{ + auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals(component.ownMethods()); + types.emplace_back(moduleId, + Utils::SmallString{component.internalName()}, + Storage::NativeType{Utils::SmallString{component.baseTypeName()}}, + createTypeAccessSemantics(component.accessSemantics()), + sourceId, + createExports(moduleId, component.exports()), + createProperties(component.ownProperties()), + std::move(functionsDeclarations), + std::move(signalDeclarations), + createEnumeration(component.ownEnumerations())); +} + +void addTypes(Storage::Types &types, + SourceId sourceId, + ModuleId moduleId, + const QHash &objects) +{ + types.reserve(Utils::usize(objects) + types.size()); + + for (const auto &object : objects) + addType(types, sourceId, moduleId, *object.get()); +} + +} // namespace + +void QmlTypesParser::parse(const QString &sourceContent, + Storage::Imports &imports, + Storage::Types &types, + SourceId sourceId, + ModuleId moduleId) +{ + QQmlJSTypeDescriptionReader reader({}, sourceContent); + QHash components; + QStringList dependencies; + bool isValid = reader(&components, &dependencies); + if (!isValid) + throw CannotParseQmlTypesFile{}; + + addImports(imports, sourceId, dependencies); + addTypes(types, sourceId, moduleId, components); +} + +} // namespace QmlDesigner diff --git a/tests/unit/unittest/qmldom-test.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h similarity index 57% rename from tests/unit/unittest/qmldom-test.cpp rename to src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h index b7e8557f10e..04733f3ecdc 100644 --- a/tests/unit/unittest/qmldom-test.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -23,29 +23,40 @@ ** ****************************************************************************/ -#include "googletest.h" +#pragma once -// cast of the top level items (DomEnvironments,...) -#include +#include "nonlockingmutex.h" +#include "qmltypesparserinterface.h" -// everything is in the QQmlJS::Dom namespace -using namespace QQmlJS::Dom; - -namespace { - -class QmlDom : public ::testing::Test -{ -public: -// static void SetUpTestCase(); -// static void TearDownTestCase(); - -protected: -}; - -TEST_F(QmlDom, First) -{ - DomItem env = DomEnvironment::create({}, DomEnvironment::Option::SingleThreaded - | DomEnvironment::Option::NoDependencies); +namespace Sqlite { +class Database; } -} // anonymous +namespace QmlDesigner { + +template +class ProjectStorage; + +template +class SourcePathCache; + +class QmlTypesParser : public QmlTypesParserInterface +{ +public: + using PathCache = QmlDesigner::SourcePathCache, + NonLockingMutex>; + + QmlTypesParser(PathCache &pathCache) + : m_pathCache{pathCache} + {} + + void parse(const QString &sourceContent, + Storage::Imports &imports, + Storage::Types &types, + SourceId sourceId, + ModuleId moduleId) override; + +private: + PathCache &m_pathCache; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h index 40c98838353..d3b102954c0 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h @@ -37,7 +37,8 @@ public: virtual void parse(const QString &sourceContent, Storage::Imports &imports, Storage::Types &types, - SourceIds &sourceIds) + SourceId sourceId, + ModuleId moduleId) = 0; protected: diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index 6252f4517d5..36aa86e6312 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -481,8 +481,7 @@ get_filename_component( ABSOLUTE ) - -if (EXISTS ../../../../qmldom_standalone/src/qmldom/standalone) +if(EXISTS ${QMLDOM_STANDALONE_CMAKELISTS} AND Qt6_FOUND) add_subdirectory( ../../../../qmldom_standalone/src/qmldom/standalone ${CMAKE_CURRENT_BINARY_DIR}/qmldom_standalone) @@ -491,9 +490,16 @@ if (EXISTS ../../../../qmldom_standalone/src/qmldom/standalone) RUNTIME_OUTPUT_DIRECTORY "$" LIBRARY_OUTPUT_DIRECTORY "$") - extend_qtc_test(unittest - DEPENDS qmldomlib - SOURCES - qmldom-test.cpp + extend_qtc_test(unittest + DEPENDS qmldomlib + SOURCES + qmldocumentparser-test.cpp + qmltypesparser-test.cpp + ) + extend_qtc_test(unittest + SOURCES_PREFIX "${QmlDesignerDir}/designercore" + SOURCES + projectstorage/qmldocumentparser.cpp projectstorage/qmldocumentparser.h + projectstorage/qmltypesparser.cpp projectstorage/qmltypesparser.h ) endif() diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 89577c1f051..85ff406f953 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -934,7 +934,7 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag) { } // namespace ClangTools namespace QmlDesigner { - +namespace { const char *sourceTypeToText(SourceType sourceType) { switch (sourceType) { @@ -950,6 +950,7 @@ const char *sourceTypeToText(SourceType sourceType) return ""; } +} // namespace std::ostream &operator<<(std::ostream &out, const FileStatus &fileStatus) { @@ -1015,8 +1016,8 @@ TypeAccessSemantics cleanFlags(TypeAccessSemantics accessSemantics) const char *typeAccessSemanticsToString(TypeAccessSemantics accessSemantics) { switch (cleanFlags(accessSemantics)) { - case TypeAccessSemantics::Invalid: - return "Invalid"; + case TypeAccessSemantics::None: + return "None"; case TypeAccessSemantics::Reference: return "Reference"; case TypeAccessSemantics::Sequence: @@ -1055,6 +1056,20 @@ const char *isQualifiedToString(IsQualified isQualified) return ""; } +const char *importKindToText(ImportKind kind) +{ + switch (kind) { + case ImportKind::Module: + return "Module"; + case ImportKind::Directory: + return "Directory"; + case ImportKind::QmlTypesDependency: + return "QmlTypesDependency"; + } + + return ""; +} + } // namespace std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics) @@ -1176,9 +1191,15 @@ std::ostream &operator<<(std::ostream &out, const Module &module) return out << "(" << module.name << ", " << module.sourceId << ")"; } +std::ostream &operator<<(std::ostream &out, const ImportKind &importKind) +{ + return out << importKindToText(importKind); +} + std::ostream &operator<<(std::ostream &out, const Import &import) { - return out << "(" << import.name << ", " << import.version << ", " << import.sourceId << ")"; + return out << "(" << import.name << ", " << import.version << ", " << import.sourceId << ", " + << import.moduleId << ", " << import.kind << ")"; } } // namespace Storage diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index d2c20d92b5f..5b8cb51e8e3 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -262,6 +262,7 @@ class EnumerationDeclaration; class EnumeratorDeclaration; class Module; class ModuleDependency; +enum class ImportKind : char; class Import; enum class IsQualified : int; @@ -282,6 +283,7 @@ std::ostream &operator<<(std::ostream &out, const EnumerationDeclaration &enumer std::ostream &operator<<(std::ostream &out, const EnumeratorDeclaration &enumeratorDeclaration); std::ostream &operator<<(std::ostream &out, const Module &module); std::ostream &operator<<(std::ostream &out, const ModuleDependency &module); +std::ostream &operator<<(std::ostream &out, const ImportKind &importKind); std::ostream &operator<<(std::ostream &out, const Import &import); std::ostream &operator<<(std::ostream &out, IsQualified isQualified); diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp index d198587821e..d6a26bb1094 100644 --- a/tests/unit/unittest/projectstorageupdater-test.cpp +++ b/tests/unit/unittest/projectstorageupdater-test.cpp @@ -305,8 +305,8 @@ TEST_F(ProjectStorageUpdater, ParseQmlTypes) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example2.qmltypes")))) .WillByDefault(Return(qmltypes2)); - EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)); - EXPECT_CALL(qmlTypesParserMock, parse(qmltypes2, _, _, _)); + EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)); + EXPECT_CALL(qmlTypesParserMock, parse(qmltypes2, _, _, _, _)); updater.update(); } @@ -334,8 +334,8 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes) QString qmltypes{"Module {\ndependencies: []}"}; ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) .WillByDefault(Return(qmltypes)); - ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)) - .WillByDefault([&](auto, auto &imports, auto &types, auto &sourceIds) { + ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)) + .WillByDefault([&](auto, auto &imports, auto &types, auto, auto) { types.push_back(objectType); imports.push_back(import); }); @@ -356,10 +356,9 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged) QString qmltypes{"Module {\ndependencies: []}"}; ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) .WillByDefault(Return(qmltypes)); - ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)) - .WillByDefault([&](auto, auto &imports, auto &types, auto &sourceIds) { - types.push_back(objectType); - }); + ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)) + .WillByDefault( + [&](auto, auto &imports, auto &types, auto, auto) { types.push_back(objectType); }); ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId))) .WillByDefault(Return(FileStatus{qmltypesPathSourceId, 2, 421})); ON_CALL(fileSystemMock, fileStatus(Eq(qmltypes2PathSourceId))) diff --git a/tests/unit/unittest/qmldocumentparser-test.cpp b/tests/unit/unittest/qmldocumentparser-test.cpp new file mode 100644 index 00000000000..4cadf8253d7 --- /dev/null +++ b/tests/unit/unittest/qmldocumentparser-test.cpp @@ -0,0 +1,243 @@ +/**************************************************************************** +** +** 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 +#include +#include + +namespace { + +namespace Storage = QmlDesigner::Storage; +using QmlDesigner::ModuleId; +using QmlDesigner::SourceContextId; +using QmlDesigner::SourceId; + +MATCHER_P(HasPrototype, prototype, std::string(negation ? "isn't " : "is ") + PrintToString(prototype)) +{ + const Storage::Type &type = arg; + + return Storage::ImportedTypeName{prototype} == type.prototype; +} + +MATCHER_P3(IsPropertyDeclaration, + name, + typeName, + traits, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::PropertyDeclaration{name, typeName, traits})) +{ + const Storage::PropertyDeclaration &propertyDeclaration = arg; + + return propertyDeclaration.name == name + && Storage::ImportedTypeName{typeName} == propertyDeclaration.typeName + && propertyDeclaration.traits == traits; +} + +MATCHER_P2(IsFunctionDeclaration, + name, + returnTypeName, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::FunctionDeclaration{name, returnTypeName})) +{ + const Storage::FunctionDeclaration &declaration = arg; + + return declaration.name == name && declaration.returnTypeName == returnTypeName; +} + +MATCHER_P(IsSignalDeclaration, + name, + std::string(negation ? "isn't " : "is ") + PrintToString(Storage::SignalDeclaration{name})) +{ + const Storage::SignalDeclaration &declaration = arg; + + return declaration.name == name; +} + +MATCHER_P2(IsParameter, + name, + typeName, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::ParameterDeclaration{name, typeName})) +{ + const Storage::ParameterDeclaration &declaration = arg; + + return declaration.name == name && declaration.typeName == typeName; +} + +MATCHER_P(IsEnumeration, + name, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::EnumerationDeclaration{name, {}})) +{ + const Storage::EnumerationDeclaration &declaration = arg; + + return declaration.name == name; +} + +MATCHER_P(IsEnumerator, + name, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::EnumeratorDeclaration{name})) +{ + const Storage::EnumeratorDeclaration &declaration = arg; + + return declaration.name == name && !declaration.hasValue; +} + +MATCHER_P2(IsEnumerator, + name, + value, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::EnumeratorDeclaration{name, value, true})) +{ + const Storage::EnumeratorDeclaration &declaration = arg; + + return declaration.name == name && declaration.value == value && declaration.hasValue; +} + +class QmlDocumentParser : public ::testing::Test +{ +public: +protected: + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; + QmlDesigner::ProjectStorage storage{database, database.isInitialized()}; + QmlDesigner::SourcePathCache> sourcePathCache{ + storage}; + QmlDesigner::QmlDocumentParser parser{sourcePathCache}; + Storage::Imports imports; + SourceId qmlFileSourceId{sourcePathCache.sourceId("path/to/qmlfile.qml")}; + SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)}; + SourceId directorySourceId{sourcePathCache.sourceId("path/to/.")}; + ModuleId directoryModuleId{&directorySourceId}; +}; + +TEST_F(QmlDocumentParser, Prototype) +{ + auto type = parser.parse("Example{}", imports, qmlFileSourceId, qmlFileSourceContextId); + + ASSERT_THAT(type, HasPrototype(Storage::ImportedType("Example"))); +} + +TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype) +{ + auto type = parser.parse("import Example as Example\n Example.Item{}", + imports, + qmlFileSourceId, + qmlFileSourceContextId); + + ASSERT_THAT(type, + HasPrototype(Storage::QualifiedImportedType( + "Item", Storage::Import{"Example", Storage::Version{}, qmlFileSourceId}))); +} + +TEST_F(QmlDocumentParser, Properties) +{ + auto type = parser.parse("Example{\n property int foo\n}", + imports, + qmlFileSourceId, + qmlFileSourceContextId); + + ASSERT_THAT(type.propertyDeclarations, + UnorderedElementsAre(IsPropertyDeclaration("foo", + Storage::ImportedType{"int"}, + Storage::PropertyDeclarationTraits::None))); +} + +TEST_F(QmlDocumentParser, DISABLED_Imports) +{ + ModuleId fooDirectoryModuleId{&sourcePathCache.sourceId("path/to/foo/.")}; + auto type = parser.parse("import QtQuick\n import \"../foo\"\nExample{}", + imports, + qmlFileSourceId, + qmlFileSourceContextId); + + ASSERT_THAT(imports, + UnorderedElementsAre( + Storage::Import{Storage::Version{}, directoryModuleId, qmlFileSourceId}, + Storage::Import{Storage::Version{}, fooDirectoryModuleId, qmlFileSourceId}, + Storage::Import{"QML", Storage::Version{1, 0}, qmlFileSourceId}, + Storage::Import{"QtQml", Storage::Version{6, 0}, qmlFileSourceId}, + Storage::Import{"QtQuick", Storage::Version{}, qmlFileSourceId})); +} + +TEST_F(QmlDocumentParser, Functions) +{ + auto type = parser.parse( + "Example{\n function someScript(x, y) {}\n function otherFunction() {}\n}", + imports, + qmlFileSourceId, + qmlFileSourceContextId); + + ASSERT_THAT(type.functionDeclarations, + UnorderedElementsAre(AllOf(IsFunctionDeclaration("otherFunction", ""), + Field(&Storage::FunctionDeclaration::parameters, IsEmpty())), + AllOf(IsFunctionDeclaration("someScript", ""), + Field(&Storage::FunctionDeclaration::parameters, + ElementsAre(IsParameter("x", ""), + IsParameter("y", "")))))); +} + +TEST_F(QmlDocumentParser, Signals) +{ + auto type = parser.parse("Example{\n signal someSignal(int x, real y)\n signal signal2()\n}", + imports, + qmlFileSourceId, + qmlFileSourceContextId); + + ASSERT_THAT(type.signalDeclarations, + UnorderedElementsAre(AllOf(IsSignalDeclaration("someSignal"), + Field(&Storage::SignalDeclaration::parameters, + ElementsAre(IsParameter("x", "int"), + IsParameter("y", "real")))), + AllOf(IsSignalDeclaration("signal2"), + Field(&Storage::SignalDeclaration::parameters, IsEmpty())))); +} + +TEST_F(QmlDocumentParser, Enumeration) +{ + auto type = parser.parse("Example{\n enum Color{red, green, blue=10, white}\n enum " + "State{On,Off}\n}", + imports, + qmlFileSourceId, + qmlFileSourceContextId); + + ASSERT_THAT(type.enumerationDeclarations, + UnorderedElementsAre( + AllOf(IsEnumeration("Color"), + Field(&Storage::EnumerationDeclaration::enumeratorDeclarations, + ElementsAre(IsEnumerator("red", 0), + IsEnumerator("green", 1), + IsEnumerator("blue", 10), + IsEnumerator("white", 11)))), + AllOf(IsEnumeration("State"), + Field(&Storage::EnumerationDeclaration::enumeratorDeclarations, + ElementsAre(IsEnumerator("On", 0), IsEnumerator("Off", 1)))))); +} + +} // namespace diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp new file mode 100644 index 00000000000..fcd182b9206 --- /dev/null +++ b/tests/unit/unittest/qmltypesparser-test.cpp @@ -0,0 +1,410 @@ +/**************************************************************************** +** +** 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 +#include +#include +#include + +namespace { + +namespace Storage = QmlDesigner::Storage; +using QmlDesigner::ModuleId; +using QmlDesigner::SourceContextId; +using QmlDesigner::SourceId; + +MATCHER_P4(IsImport, + name, + version, + sourceId, + kind, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::Import{name, version, sourceId, kind})) +{ + const Storage::Import &import = arg; + + return import.name == name && import.version == version && import.sourceId == sourceId + && import.kind == kind; +} + +MATCHER_P(HasPrototype, prototype, std::string(negation ? "isn't " : "is ") + PrintToString(prototype)) +{ + const Storage::Type &type = arg; + + return Storage::ImportedTypeName{prototype} == type.prototype; +} + +MATCHER_P5(IsType, + moduleId, + typeName, + prototype, + accessSemantics, + sourceId, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::Type{moduleId, typeName, prototype, accessSemantics, sourceId})) +{ + const Storage::Type &type = arg; + + return type.moduleId == moduleId && type.typeName == typeName + && type.prototype == Storage::ImportedTypeName{prototype} + && type.accessSemantics == accessSemantics && type.sourceId == sourceId; +} + +MATCHER_P3(IsPropertyDeclaration, + name, + typeName, + traits, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::PropertyDeclaration{name, typeName, traits})) +{ + const Storage::PropertyDeclaration &propertyDeclaration = arg; + + return propertyDeclaration.name == name + && Storage::ImportedTypeName{typeName} == propertyDeclaration.typeName + && propertyDeclaration.traits == traits + && propertyDeclaration.kind == Storage::PropertyKind::Property; +} + +MATCHER_P2(IsFunctionDeclaration, + name, + returnTypeName, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::FunctionDeclaration{name, returnTypeName})) +{ + const Storage::FunctionDeclaration &declaration = arg; + + return declaration.name == name && declaration.returnTypeName == returnTypeName; +} + +MATCHER_P(IsSignalDeclaration, + name, + std::string(negation ? "isn't " : "is ") + PrintToString(Storage::SignalDeclaration{name})) +{ + const Storage::SignalDeclaration &declaration = arg; + + return declaration.name == name; +} + +MATCHER_P2(IsParameter, + name, + typeName, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::ParameterDeclaration{name, typeName})) +{ + const Storage::ParameterDeclaration &declaration = arg; + + return declaration.name == name && declaration.typeName == typeName; +} + +MATCHER_P(IsEnumeration, + name, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::EnumerationDeclaration{name, {}})) +{ + const Storage::EnumerationDeclaration &declaration = arg; + + return declaration.name == name; +} + +MATCHER_P(IsEnumerator, + name, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::EnumeratorDeclaration{name})) +{ + const Storage::EnumeratorDeclaration &declaration = arg; + + return declaration.name == name && !declaration.hasValue; +} + +MATCHER_P2(IsEnumerator, + name, + value, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::EnumeratorDeclaration{name, value, true})) +{ + const Storage::EnumeratorDeclaration &declaration = arg; + + return declaration.name == name && declaration.value == value && declaration.hasValue; +} + +MATCHER_P3(IsExportedType, + moduleId, + name, + version, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::ExportedType{moduleId, name, version})) +{ + const Storage::ExportedType &type = arg; + + return type.name == name && type.moduleId == moduleId && type.version == version; +} + +class QmlTypesParser : public ::testing::Test +{ +public: +protected: + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; + QmlDesigner::ProjectStorage storage{database, database.isInitialized()}; + QmlDesigner::SourcePathCache> sourcePathCache{ + storage}; + QmlDesigner::QmlTypesParser parser{sourcePathCache}; + Storage::Imports imports; + Storage::Types types; + SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")}; + SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)}; + SourceId directorySourceId{sourcePathCache.sourceId("path/to/.")}; + ModuleId directoryModuleId{&directorySourceId}; +}; + +TEST_F(QmlTypesParser, Imports) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + dependencies: + ["QtQuick 2.15", "QtQuick.Window 2.1", "QtFoo 6"]})"}; + + parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + + ASSERT_THAT(imports, + UnorderedElementsAre(IsImport("QtQuick", + Storage::Version{2, 15}, + qmltypesFileSourceId, + Storage::ImportKind::QmlTypesDependency), + IsImport("QtQuick.Window", + Storage::Version{2, 1}, + qmltypesFileSourceId, + Storage::ImportKind::QmlTypesDependency), + IsImport("QML", + Storage::Version{}, + qmltypesFileSourceId, + Storage::ImportKind::QmlTypesDependency), + IsImport("QtQml", + Storage::Version{}, + qmltypesFileSourceId, + Storage::ImportKind::QmlTypesDependency), + IsImport("QtFoo", + Storage::Version{6}, + qmltypesFileSourceId, + Storage::ImportKind::QmlTypesDependency))); +} + +TEST_F(QmlTypesParser, Types) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "QObject"} + Component { name: "QQmlComponent" + prototype: "QObject"}})"}; + + parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + + ASSERT_THAT(types, + UnorderedElementsAre(IsType(directoryModuleId, + "QObject", + Storage::NativeType{}, + Storage::TypeAccessSemantics::Reference, + qmltypesFileSourceId), + IsType(directoryModuleId, + "QQmlComponent", + Storage::NativeType{"QObject"}, + Storage::TypeAccessSemantics::Reference, + qmltypesFileSourceId))); +} + +TEST_F(QmlTypesParser, ExportedTypes) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "QObject" + exports: ["QtQml/QtObject 1.0", "QtQml/QtObject 2.1"] + }})"}; + + parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + + ASSERT_THAT( + types, + ElementsAre( + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(directoryModuleId, "QtObject", Storage::Version{1, 0}), + IsExportedType(directoryModuleId, "QtObject", Storage::Version{2, 1}))))); +} + +TEST_F(QmlTypesParser, Properties) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "QObject" + Property { name: "objectName"; type: "string" } + Property { name: "target"; type: "QObject"; isPointer: true } + Property { name: "progress"; type: "double"; isReadonly: true } + Property { name: "targets"; type: "QQuickItem"; isList: true; isReadonly: true; isPointer: true } + }})"}; + + parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + + ASSERT_THAT(types, + ElementsAre(Field( + &Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("objectName", + Storage::NativeType{"string"}, + Storage::PropertyDeclarationTraits::None), + IsPropertyDeclaration("target", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsPointer), + IsPropertyDeclaration("progress", + Storage::NativeType{"double"}, + Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("targets", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsReadOnly + | Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsPointer))))); +} + +TEST_F(QmlTypesParser, Functions) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "QObject" + Method { name: "movieUpdate" } + Method { + name: "advance" + Parameter { name: "frames"; type: "int" } + Parameter { name: "fps"; type: "double" } + } + Method { + name: "isImageLoading" + type: "bool" + Parameter { name: "url"; type: "QUrl" } + } + Method { + name: "getContext" + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } + } + }})"}; + + parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + + ASSERT_THAT(types, + ElementsAre( + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre( + AllOf(IsFunctionDeclaration("advance", ""), + Field(&Storage::FunctionDeclaration::parameters, + UnorderedElementsAre(IsParameter("frames", "int"), + IsParameter("fps", "double")))), + AllOf(IsFunctionDeclaration("isImageLoading", "bool"), + Field(&Storage::FunctionDeclaration::parameters, + UnorderedElementsAre(IsParameter("url", "QUrl")))), + AllOf(IsFunctionDeclaration("getContext", ""), + Field(&Storage::FunctionDeclaration::parameters, + UnorderedElementsAre(IsParameter("args", "QQmlV4Function")))), + AllOf(IsFunctionDeclaration("movieUpdate", ""), + Field(&Storage::FunctionDeclaration::parameters, IsEmpty())))))); +} + +TEST_F(QmlTypesParser, Signals) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "QObject" + Method { name: "movieUpdate" } + Signal { + name: "advance" + Parameter { name: "frames"; type: "int" } + Parameter { name: "fps"; type: "double" } + } + Signal { + name: "isImageLoading" + Parameter { name: "url"; type: "QUrl" } + } + Signal { + name: "getContext" + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } + } + }})"}; + + parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + + ASSERT_THAT(types, + ElementsAre(Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre( + AllOf(IsSignalDeclaration("advance"), + Field(&Storage::SignalDeclaration::parameters, + UnorderedElementsAre(IsParameter("frames", "int"), + IsParameter("fps", "double")))), + AllOf(IsSignalDeclaration("isImageLoading"), + Field(&Storage::SignalDeclaration::parameters, + UnorderedElementsAre(IsParameter("url", "QUrl")))), + AllOf(IsSignalDeclaration("getContext"), + Field(&Storage::SignalDeclaration::parameters, + UnorderedElementsAre( + IsParameter("args", "QQmlV4Function")))))))); +} + +TEST_F(QmlTypesParser, Enumerations) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "QObject" + Enum { + name: "NamedColorSpace" + values: [ + "Unknown", + "SRgb", + "AdobeRgb", + "DisplayP3", + ] + } + Enum { + name: "VerticalLayoutDirection" + values: ["TopToBottom", "BottomToTop"] + } + }})"}; + + parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + + ASSERT_THAT(types, + ElementsAre( + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre( + AllOf(IsEnumeration("NamedColorSpace"), + Field(&Storage::EnumerationDeclaration::enumeratorDeclarations, + UnorderedElementsAre(IsEnumerator("Unknown"), + IsEnumerator("SRgb"), + IsEnumerator("AdobeRgb"), + IsEnumerator("DisplayP3")))), + AllOf(IsEnumeration("VerticalLayoutDirection"), + Field(&Storage::EnumerationDeclaration::enumeratorDeclarations, + UnorderedElementsAre(IsEnumerator("TopToBottom"), + IsEnumerator("BottomToTop")))))))); +} + +} // namespace diff --git a/tests/unit/unittest/qmltypesparsermock.h b/tests/unit/unittest/qmltypesparsermock.h index 337c0f05ff8..cfbb8729841 100644 --- a/tests/unit/unittest/qmltypesparsermock.h +++ b/tests/unit/unittest/qmltypesparsermock.h @@ -37,6 +37,7 @@ public: (const QString &sourceContent, QmlDesigner::Storage::Imports &imports, QmlDesigner::Storage::Types &types, - QmlDesigner::SourceIds &sourceIds), + QmlDesigner::SourceId sourceId, + QmlDesigner::ModuleId moduleId), (override)); }; From c92deea33fa5e819ef3e324fb15b11ff1935fd69 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 12 Oct 2021 13:44:35 +0200 Subject: [PATCH 053/117] ClangCodeModel: Provide source of diagnostics in tooltip It's helpful to know whether a particular issue came from clangd, libclang, or somewhere else. Change-Id: I9e00d79ffe630a91028c2aeff219571e9979dbee Reviewed-by: David Schulz --- .../clangdiagnostictooltipwidget.cpp | 24 +++++++++++++------ .../clangdiagnostictooltipwidget.h | 3 ++- .../clangeditordocumentprocessor.cpp | 3 ++- src/plugins/clangcodemodel/clangtextmark.cpp | 4 ++-- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp index ffdd3c43969..195c4f4ead9 100644 --- a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp +++ b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp @@ -104,9 +104,9 @@ public: } QWidget *createWidget(const QVector &diagnostics, - const std::function &canApplyFixIt) + const std::function &canApplyFixIt, const QString &source) { - const QString text = htmlText(diagnostics); + const QString text = htmlText(diagnostics, source); auto *label = new QLabel; label->setTextFormat(Qt::RichText); @@ -154,13 +154,20 @@ public: return label; } - QString htmlText(const QVector &diagnostics) + QString htmlText(const QVector &diagnostics, + const QString &source) { // For debugging, add: style='border-width:1px;border-color:black' QString text = ""; foreach (const ClangBackEnd::DiagnosticContainer &diagnostic, diagnostics) text.append(tableRows(diagnostic)); + if (!source.isEmpty()) { + text.append(QString::fromUtf8("") + .arg(QCoreApplication::translate("ClangDiagnosticWidget", "[Source: %1]")) + .arg(source)); + } text.append("
" + "%1
"); @@ -396,7 +403,8 @@ QString ClangDiagnosticWidget::createText( const QVector &diagnostics, const ClangDiagnosticWidget::Destination &destination) { - const QString htmlText = WidgetFromDiagnostics(toHints(destination, {})).htmlText(diagnostics); + const QString htmlText = WidgetFromDiagnostics(toHints(destination, {})) + .htmlText(diagnostics, {}); QTextDocument document; document.setHtml(htmlText); @@ -410,11 +418,13 @@ QString ClangDiagnosticWidget::createText( return text; } -QWidget *ClangDiagnosticWidget::createWidget(const QVector &diagnostics, - const Destination &destination, const std::function &canApplyFixIt) +QWidget *ClangDiagnosticWidget::createWidget( + const QVector &diagnostics, + const Destination &destination, const std::function &canApplyFixIt, + const QString &source) { return WidgetFromDiagnostics(toHints(destination, canApplyFixIt)) - .createWidget(diagnostics, canApplyFixIt); + .createWidget(diagnostics, canApplyFixIt, source); } } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.h b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.h index afe35812ae0..92f98a59cae 100644 --- a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.h +++ b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.h @@ -48,7 +48,8 @@ public: static QWidget *createWidget(const QVector &diagnostics, const Destination &destination, - const std::function &canApplyFixIt); + const std::function &canApplyFixIt, + const QString &source); }; } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index a9d4f01c726..94a44085056 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -506,7 +506,8 @@ ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget( vbox->setSpacing(2); vbox->addWidget(ClangDiagnosticWidget::createWidget({firstHeaderErrorDiagnostic}, - ClangDiagnosticWidget::InfoBar, {})); + ClangDiagnosticWidget::InfoBar, {}, + "libclang")); auto widget = new QWidget; widget->setLayout(vbox); diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index 38227008a9b..01cfae6ae6f 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -281,7 +281,7 @@ bool ClangTextMark::addToolTipContent(QLayout *target) const && diagMgr->diagnosticsWithFixIts().contains(diag); }; QWidget *widget = ClangDiagnosticWidget::createWidget( - {m_diagnostic}, ClangDiagnosticWidget::ToolTip, canApplyFixIt); + {m_diagnostic}, ClangDiagnosticWidget::ToolTip, canApplyFixIt, "libclang"); target->addWidget(widget); return true; @@ -398,7 +398,7 @@ bool ClangdTextMark::addToolTipContent(QLayout *target) const return c && c->reachable() && c->hasDiagnostic(DocumentUri::fromFilePath(fp), diag); }; target->addWidget(ClangDiagnosticWidget::createWidget({m_diagnostic}, - ClangDiagnosticWidget::ToolTip, canApplyFixIt)); + ClangDiagnosticWidget::ToolTip, canApplyFixIt, "clangd")); return true; } From 6bf7521a89da714a21cdf47f721782197a21f057 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 14 Oct 2021 08:34:44 +0200 Subject: [PATCH 054/117] CppEditor: check result line before finding block Task-number: QTCREATORBUG-26396 Change-Id: Iccd6df3495336ff550da6f1fd1f9c17c588a80e3 Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/semantichighlighter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp index f3112a725be..eb6e90fb2b9 100644 --- a/src/plugins/cppeditor/semantichighlighter.cpp +++ b/src/plugins/cppeditor/semantichighlighter.cpp @@ -180,6 +180,7 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) QPair parentheses; for (int i = from; i < to; ++i) { const HighlightingResult &result = m_watcher->future().resultAt(i); + QTC_ASSERT(result.line <= m_baseTextDocument->document()->blockCount(), continue); if (result.kind != AngleBracketOpen && result.kind != AngleBracketClose && result.kind != DoubleAngleBracketClose && result.kind != TernaryIf && result.kind != TernaryElse) { From d9dd3612da88c237172744111fbb4f422d48eaa3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 13 Oct 2021 14:24:25 +0200 Subject: [PATCH 055/117] ClangCodeModel: Fix QStringView crashes Some AST nodes have no range, triggering crashes in QStringView::mid(). Rather than checking all callers, we just use a safe variant. Change-Id: I3c8d388693f9161249f201ecd4e8bad933463960 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 44 ++++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 01bd5b6c2a7..db8f275b4df 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -98,6 +98,25 @@ static Q_LOGGING_CATEGORY(clangdLogHighlight, "qtc.clangcodemodel.clangd.highlig static Q_LOGGING_CATEGORY(clangdLogTiming, "qtc.clangcodemodel.clangd.timing", QtWarningMsg); static QString indexingToken() { return "backgroundIndexProgress"; } +static QStringView subView(const QString &s, qsizetype start) +{ + if (start < 0 || start > s.length()) + return {}; + return QStringView(s).mid(start); +} + +static QStringView subViewLen(const QString &s, qsizetype start, qsizetype length) +{ + if (start < 0 || length < 0 || start + length > s.length()) + return {}; + return QStringView(s).mid(start, length); +} + +static QStringView subViewEnd(const QString &s, qsizetype start, qsizetype end) +{ + return subViewLen(s, start, end - start); +} + class AstNode : public JsonObject { public: @@ -2197,7 +2216,7 @@ static QList cleanupDisabledCode(HighlightingResults &results, const if (!wasIfdefedOut) rangeStartPos = doc->findBlockByNumber(it->line - 1).position(); const int pos = Utils::Text::positionInText(doc, it->line, it->column); - const QStringView content(QStringView(docContent).mid(pos, it->length).trimmed()); + const QStringView content = subViewLen(docContent, pos, it->length).trimmed(); if (!content.startsWith(QLatin1String("#if")) && !content.startsWith(QLatin1String("#elif")) && !content.startsWith(QLatin1String("#else")) @@ -2646,11 +2665,9 @@ bool ClangdClient::ClangdCompletionAssistProvider::isInCommentOrString( const QString &line = tc.block().text(); const Token &idToken = tokens.at(1); QStringView identifier = idToken.utf16charsEnd() > line.size() - ? QStringView(line).mid( - idToken.utf16charsBegin()) - : QStringView(line) - .mid(idToken.utf16charsBegin(), - idToken.utf16chars()); + ? subView(line, idToken.utf16charsBegin()) + : subViewLen(line, idToken.utf16charsBegin(), + idToken.utf16chars()); if (identifier == QLatin1String("include") || identifier == QLatin1String("include_next") || (CppEditor::ProjectFile::isObjC(interface->filePath().toString()) @@ -2944,7 +2961,7 @@ void ExtraHighlightingResultsCollector::insertAngleBracketInfo(int searchStart1, int searchStart2, int searchEnd2) { const int openingAngleBracketPos = onlyIndexOf( - QStringView(m_docContent).mid(searchStart1, searchEnd1 - searchStart1), + subViewEnd(m_docContent, searchStart1, searchEnd1), QStringView(QStringLiteral("<"))); if (openingAngleBracketPos == -1) return; @@ -2954,7 +2971,7 @@ void ExtraHighlightingResultsCollector::insertAngleBracketInfo(int searchStart1, if (searchStart2 >= searchEnd2) return; const int closingAngleBracketPos = onlyIndexOf( - QStringView(m_docContent).mid(searchStart2, searchEnd2 - searchStart2), + subViewEnd(m_docContent, searchStart2, searchEnd2), QStringView(QStringLiteral(">"))); if (closingAngleBracketPos == -1) return; @@ -3032,16 +3049,14 @@ void ExtraHighlightingResultsCollector::collectFromNode(const AstNode &node) // sub-expressions 2 and 3. const int searchStartPosQuestionMark = posForNodeEnd(children.first()); const int searchEndPosQuestionMark = posForNodeStart(children.at(1)); - QStringView content = QStringView(m_docContent).mid( - searchStartPosQuestionMark, - searchEndPosQuestionMark - searchStartPosQuestionMark); + QStringView content = subViewEnd(m_docContent, searchStartPosQuestionMark, + searchEndPosQuestionMark); const int questionMarkPos = onlyIndexOf(content, QStringView(QStringLiteral("?"))); if (questionMarkPos == -1) return; const int searchStartPosColon = posForNodeEnd(children.at(1)); const int searchEndPosColon = posForNodeStart(children.at(2)); - content = QStringView(m_docContent).mid(searchStartPosColon, - searchEndPosColon - searchStartPosColon); + content = subViewEnd(m_docContent, searchStartPosColon, searchEndPosColon); const int colonPos = onlyIndexOf(content, QStringView(QStringLiteral(":"))); if (colonPos == -1) return; @@ -3218,8 +3233,7 @@ void ExtraHighlightingResultsCollector::collectFromNode(const AstNode &node) if (isDeclaration) result.textStyles.mixinStyles.push_back(C_DECLARATION); - const QStringView nodeText = QStringView(m_docContent) - .mid(nodeStartPos, nodeEndPos - nodeStartPos); + const QStringView nodeText = subViewEnd(m_docContent, nodeStartPos, nodeEndPos); if (isCallToNew || isCallToDelete) { result.line = node.range().start().line() + 1; From 0543a810e59750cae28450bafa935a32c599f73b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 7 Oct 2021 16:55:51 +0200 Subject: [PATCH 056/117] Bump version to 6.0.0-beta2 Change-Id: If15ba5f3b6484a7b649baac5bd0eb25147cc10db Reviewed-by: David Schulz --- cmake/QtCreatorIDEBranding.cmake | 6 +++--- qbs/modules/qtc/qtc.qbs | 6 +++--- qtcreator_ide_branding.pri | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 3a95d32847f..1a89b8888f9 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ -set(IDE_VERSION "5.82.0") # The IDE version. -set(IDE_VERSION_COMPAT "5.82.0") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "6.0.0-beta1") # The IDE display version. +set(IDE_VERSION "5.83.0") # The IDE version. +set(IDE_VERSION_COMPAT "5.83.0") # The IDE Compatibility version. +set(IDE_VERSION_DISPLAY "6.0.0-beta2") # The IDE display version. set(IDE_COPYRIGHT_YEAR "2021") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index f27b2d2880a..e6e984ad719 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -3,15 +3,15 @@ import qbs.Environment import qbs.FileInfo Module { - property string qtcreator_display_version: '6.0.0-beta1' + property string qtcreator_display_version: '6.0.0-beta2' property string ide_version_major: '5' - property string ide_version_minor: '82' + property string ide_version_minor: '83' property string ide_version_release: '0' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release property string ide_compat_version_major: '5' - property string ide_compat_version_minor: '82' + property string ide_compat_version_minor: '83' property string ide_compat_version_release: '0' property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release diff --git a/qtcreator_ide_branding.pri b/qtcreator_ide_branding.pri index 97dcce11c16..79f08928717 100644 --- a/qtcreator_ide_branding.pri +++ b/qtcreator_ide_branding.pri @@ -1,6 +1,6 @@ -QTCREATOR_VERSION = 5.82.0 -QTCREATOR_COMPAT_VERSION = 5.82.0 -QTCREATOR_DISPLAY_VERSION = 6.0.0-beta1 +QTCREATOR_VERSION = 5.83.0 +QTCREATOR_COMPAT_VERSION = 5.83.0 +QTCREATOR_DISPLAY_VERSION = 6.0.0-beta2 QTCREATOR_COPYRIGHT_YEAR = 2021 IDE_DISPLAY_NAME = Qt Creator From c099f622bb50b6b42ddca030ba4062dee7cf8752 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 12 Oct 2021 00:28:19 +0200 Subject: [PATCH 057/117] Core: Allow dialogs and popups be styled as "panelwidgets" A recent change that prevented popups from being styled as "panelwidget" unintentionally removed the styling from the upper part of the mini target chooser. This change re-allows styling contents of popups (and dialogs) if they have the "panelwidget" property set to true. Amends: 0786e967ddb52a2c744576ae9dbc7ec4844b9581 Fixes: QTCREATORBUG-26403 Change-Id: Ib85b06d0a2823a5caf736d1354cf025a6ddd475c Reviewed-by: Christian Stenger --- src/plugins/coreplugin/manhattanstyle.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 50837d9f153..a6b94660f6f 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -73,10 +73,13 @@ bool styleEnabled(const QWidget *widget) return true; } -static bool isInDialogOrPopup(const QWidget *widget) +static bool isInUnstyledDialogOrPopup(const QWidget *widget) { - // Do not style dialogs or explicitly ignored widgets - const Qt::WindowType windowType = widget->window()->windowType(); + // Do not style contents of dialogs or popups without "panelwidget" property + const QWidget *window = widget->window(); + if (window->property("panelwidget").toBool()) + return false; + const Qt::WindowType windowType = window->windowType(); return (windowType == Qt::Dialog || windowType == Qt::Popup); } @@ -86,7 +89,7 @@ bool panelWidget(const QWidget *widget) if (!widget) return false; - if (isInDialogOrPopup(widget)) + if (isInUnstyledDialogOrPopup(widget)) return false; if (qobject_cast(widget)) @@ -113,7 +116,7 @@ bool lightColored(const QWidget *widget) if (!widget) return false; - if (isInDialogOrPopup(widget)) + if (isInUnstyledDialogOrPopup(widget)) return false; const QWidget *p = widget; From a19da3af749c2131eb3c73c74b72d0324feb3653 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 14 Oct 2021 09:01:03 +0300 Subject: [PATCH 058/117] ElfReader: Fix running locally Amends commit 736820a1a0b1348beb4f0d8c690455de5926cebe. Change-Id: Id0a8aa9b0939e53f6eafc7b9f0e1cb821883e90a Reviewed-by: Christian Stenger --- src/libs/utils/elfreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/elfreader.cpp b/src/libs/utils/elfreader.cpp index 3ff33880414..1883585bc86 100644 --- a/src/libs/utils/elfreader.cpp +++ b/src/libs/utils/elfreader.cpp @@ -113,7 +113,7 @@ bool ElfMapper::map() return fdlen > 0; } - file.setFileName(binary.fileName()); + file.setFileName(binary.path()); if (!file.open(QIODevice::ReadOnly)) return false; From 57fccec1d7c1d5eb5b3cab57945f910dc4c33cc4 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 14 Oct 2021 15:05:31 +0200 Subject: [PATCH 059/117] ProjectExplorer: Do not run the build output parser test from a thread Tasks must only be created in the main thread. Change-Id: I7d0e6f850bec3eb1d700ffa8fdba0c2e253d47aa Reviewed-by: Jarek Kobus --- .../projectexplorer/parseissuesdialog.cpp | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp index 75be7e7bcb2..f81db2da7d2 100644 --- a/src/plugins/projectexplorer/parseissuesdialog.cpp +++ b/src/plugins/projectexplorer/parseissuesdialog.cpp @@ -32,9 +32,6 @@ #include "projectexplorerconstants.h" #include "taskhub.h" -#include -#include - #include #include #include @@ -137,21 +134,6 @@ ParseIssuesDialog::~ParseIssuesDialog() delete d; } -static void parse(QFutureInterface &future, const QString &output, - const std::unique_ptr &parser, bool isStderr) -{ - const QStringList lines = output.split('\n'); - future.setProgressRange(0, lines.count()); - const Utils::OutputFormat format = isStderr ? Utils::StdErrFormat : Utils::StdOutFormat; - for (const QString &line : lines) { - parser->appendMessage(line + '\n', format); - future.setProgressValue(future.progressValue() + 1); - if (future.isCanceled()) - return; - } - parser->flush(); -} - void ParseIssuesDialog::accept() { const QList lineParsers = @@ -161,14 +143,16 @@ void ParseIssuesDialog::accept() "not provide an output parser.")); return; } - std::unique_ptr parser(new Utils::OutputFormatter); - parser->setLineParsers(lineParsers); + Utils::OutputFormatter parser; + parser.setLineParsers(lineParsers); if (d->clearTasksCheckBox.isChecked()) TaskHub::clearTasks(); - const QFuture f = Utils::runAsync(&parse, d->compileOutputEdit.toPlainText(), - std::move(parser), d->stderrCheckBox.isChecked()); - Core::ProgressManager::addTask(f, tr("Parsing build output"), - "ProgressExplorer.ParseExternalBuildOutput"); + const QStringList lines = d->compileOutputEdit.toPlainText().split('\n'); + const Utils::OutputFormat format = d->stderrCheckBox.isChecked() + ? Utils::StdErrFormat : Utils::StdOutFormat; + for (const QString &line : lines) + parser.appendMessage(line + '\n', format); + parser.flush(); QDialog::accept(); } From e1a15b2db504a6f10d6480d81ed34a3cdd39a3c2 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 13 Oct 2021 15:41:38 +0200 Subject: [PATCH 060/117] QmlJS: Soften strict equality check Judging on the sense of a strict equality check depends on different aspects. As attached properties cannot be inspected easily and e.g. function calls cannot be evaluated as they may have different return values for different code paths we need to soften the check to avoid false positives. Fixes: QTCREATORBUG-25917 Change-Id: I121335a387eb235090346162df4703d3000b7426 Reviewed-by: Qt CI Bot Reviewed-by: Fabian Kosmale --- src/libs/qmljs/qmljscheck.cpp | 17 ++++++++++++- .../qml/codemodel/check/equality-checks.qml | 24 +++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 3ce402589c1..38595a8b363 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -1263,13 +1263,28 @@ static bool equalIsAlwaysFalse(const Value *lhs, const Value *rhs) return false; } +static bool isIntegerValue(const Value *value) +{ + if (value->asNumberValue() || value->asIntValue()) + return true; + if (auto obj = value->asObjectValue()) + return obj->className() == "Number"; + + return false; +} + static bool strictCompareConstant(const Value *lhs, const Value *rhs) { if (lhs->asUnknownValue() || rhs->asUnknownValue()) return false; + if (lhs->asFunctionValue() || rhs->asFunctionValue()) // function evaluation not implemented + return false; + if (isIntegerValue(lhs) && isIntegerValue(rhs)) + return false; if (lhs->asBooleanValue() && !rhs->asBooleanValue()) return true; - if (lhs->asNumberValue() && !rhs->asNumberValue()) + // attached properties and working at runtime cases may be undefined at evaluation time + if (lhs->asNumberValue() && (!rhs->asNumberValue() && !rhs->asUndefinedValue())) return true; if (lhs->asStringValue() && !rhs->asStringValue()) return true; diff --git a/tests/auto/qml/codemodel/check/equality-checks.qml b/tests/auto/qml/codemodel/check/equality-checks.qml index b562625c23c..0a24cccce9a 100644 --- a/tests/auto/qml/codemodel/check/equality-checks.qml +++ b/tests/auto/qml/codemodel/check/equality-checks.qml @@ -86,7 +86,7 @@ Rectangle { if (n === s) {} // 325 15 17 if (n === n) {} if (n === N) {} // 325 15 17 - if (n === u) {} // 325 15 17 + if (n === u) {} if (n === b) {} // 325 15 17 if (n === o) {} // 325 15 17 if (n === k) {} @@ -101,7 +101,7 @@ Rectangle { if (N === k) {} if (u === s) {} // 325 15 17 - if (u === n) {} // 325 15 17 + if (u === n) {} if (u === N) {} if (u === u) {} if (u === b) {} // 325 15 17 @@ -132,5 +132,25 @@ Rectangle { if (k === b) {} if (k === o) {} if (k === k) {} + + var nObj = Number("0") + var nNum = Number.fromLocaleString("0") + if (n === 1) {} + if (nObj === 1) {} + if (nNum === 1) {} + + } + + ListView { + model: ListModel{ id: myModel } + delegate: Item { + MouseArea { + anchors.fill: parent + hoverEnabled: true + onClicked: { + if (index === -1) {} + } + } + } } } From 5365dd531b881eb27d8d843fbb94983b89b74de3 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 14 Oct 2021 22:32:09 +0300 Subject: [PATCH 061/117] Fix some MSVC warnings * Implicit conversion of size_t to int * Comparing bool with operator > Change-Id: I4bc5bef57bfa0125b1c82953a7a2cfc24066bc8c Reviewed-by: hjk --- src/libs/qmldebug/qpacketprotocol.cpp | 2 +- src/libs/qmljs/qmljsmodelmanagerinterface.cpp | 4 ++-- src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp | 8 ++++---- src/plugins/debugger/watchhandler.cpp | 2 +- src/plugins/designer/codemodelhelpers.cpp | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libs/qmldebug/qpacketprotocol.cpp b/src/libs/qmldebug/qpacketprotocol.cpp index 76822d34d4d..24d4d29c54b 100644 --- a/src/libs/qmldebug/qpacketprotocol.cpp +++ b/src/libs/qmldebug/qpacketprotocol.cpp @@ -225,7 +225,7 @@ void QPacketProtocol::send(const QByteArray &p) return; } - const qint32 sendSize = p.size() + sizeof(qint32); + const qint32 sendSize = qint32(p.size() + sizeof(qint32)); d->sendingPackets.append(sendSize); const qint32 sendSizeLE = qToLittleEndian(sendSize); diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index 34048e81850..db08418ca78 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -1329,7 +1329,7 @@ bool rescanExports(const QString &fileName, FindExportedCppTypes &finder, QList exported = finder.exportedTypes(); QHash contextProperties = finder.contextProperties(); if (exported.isEmpty() && contextProperties.isEmpty()) { - hasNewInfo = hasNewInfo || newData.remove(fileName) > 0; + hasNewInfo = hasNewInfo || newData.remove(fileName); } else { ModelManagerInterface::CppData &data = newData[fileName]; if (!hasNewInfo && (data.exportedTypes.size() != exported.size() @@ -1382,7 +1382,7 @@ void ModelManagerInterface::updateCppQmlTypes( const bool scan = pair.second; const QString fileName = doc->fileName(); if (!scan) { - hasNewInfo = newData.remove(fileName) > 0 || hasNewInfo; + hasNewInfo = newData.remove(fileName) || hasNewInfo; const auto savedDocs = newDeclarations.value(fileName); for (const CPlusPlus::Document::Ptr &savedDoc : savedDocs) { finder(savedDoc); diff --git a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp index 18fcdce5dc3..9ac3cee8eeb 100644 --- a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp +++ b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp @@ -215,9 +215,9 @@ bool CdbSymbolPathListEditor::isSymbolServerPath(const QString &path, QString *c if (!path.startsWith(QLatin1String(symbolServerPrefixC)) || !path.endsWith(QLatin1String(symbolServerPostfixC))) return false; if (cacheDir) { - static const unsigned prefixLength = qstrlen(symbolServerPrefixC); - static const unsigned postfixLength = qstrlen(symbolServerPostfixC); - if (path.length() == int(prefixLength + postfixLength)) + static const unsigned prefixLength = unsigned(qstrlen(symbolServerPrefixC)); + static const unsigned postfixLength = unsigned(qstrlen(symbolServerPostfixC)); + if (unsigned(path.length()) == prefixLength + postfixLength) return true; // Split apart symbol server post/prefixes *cacheDir = path.mid(prefixLength, path.size() - prefixLength - qstrlen(symbolServerPostfixC) + 1); @@ -230,7 +230,7 @@ bool CdbSymbolPathListEditor::isSymbolCachePath(const QString &path, QString *ca if (!path.startsWith(QLatin1String(symbolCachePrefixC))) return false; if (cacheDir) { - static const unsigned prefixLength = qstrlen(symbolCachePrefixC); + static const unsigned prefixLength = unsigned(qstrlen(symbolCachePrefixC)); // Split apart symbol cach prefixes *cacheDir = path.mid(prefixLength); } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 1dc061c508c..20a5c95108b 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -133,7 +133,7 @@ template void readNumericVectorHelper(std::vector *v, const QByteArray &ba) { const auto p = (const T*)ba.data(); - const int n = ba.size() / sizeof(T); + const int n = int(ba.size() / sizeof(T)); v->resize(n); // Losing precision in case of 64 bit ints is ok here, as the result // is only used to plot data. diff --git a/src/plugins/designer/codemodelhelpers.cpp b/src/plugins/designer/codemodelhelpers.cpp index b0d91f0a74a..009bf83f53b 100644 --- a/src/plugins/designer/codemodelhelpers.cpp +++ b/src/plugins/designer/codemodelhelpers.cpp @@ -82,7 +82,7 @@ private: }; SearchFunction::SearchFunction(const char *name) : - m_length(qstrlen(name)), + m_length(uint(qstrlen(name))), m_name(name) { } From 893886487663b92cacf28f1c147b396d208b8774 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 13 Oct 2021 09:03:02 +0200 Subject: [PATCH 062/117] FakeVim: Use setEnabler for the vimrc path aspect This fixes the enabling/disabling of the line edit and triggers the (re-)read of the .vimrc at the right times. Change-Id: I13a022aafc23ea761d3c1c4d0359cc5f137695d5 Reviewed-by: Lukas Holecek Reviewed-by: Christian Stenger --- src/plugins/fakevim/fakevimplugin.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 8be735072dc..fae4f7c835d 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -380,7 +380,6 @@ private: void copyTextEditorSettings(); void setQtStyle(); void setPlainStyle(); - void updateVimRcWidgets(); }; void FakeVimOptionPage::layoutPage(QWidget *widget) @@ -449,15 +448,14 @@ void FakeVimOptionPage::layoutPage(QWidget *widget) }.attachTo(widget, true); + s.vimRcPath.setEnabler(&s.readVimRc); + connect(copyTextEditorSettings, &QAbstractButton::clicked, this, &FakeVimOptionPage::copyTextEditorSettings); connect(setQtStyle, &QAbstractButton::clicked, this, &FakeVimOptionPage::setQtStyle); connect(setPlainStyle, &QAbstractButton::clicked, this, &FakeVimOptionPage::setPlainStyle); - connect(&s.readVimRc, &FvBaseAspect::changed, - this, &FakeVimOptionPage::updateVimRcWidgets); - updateVimRcWidgets(); } void FakeVimOptionPage::copyTextEditorSettings() @@ -503,13 +501,6 @@ void FakeVimOptionPage::setPlainStyle() s.passKeys.setVolatileValue(false); } -void FakeVimOptionPage::updateVimRcWidgets() -{ - FakeVimSettings &s = *fakeVimSettings(); - s.vimRcPath.setEnabled(s.readVimRc.value()); -} - - /////////////////////////////////////////////////////////////////////// // // FakeVimPluginPrivate From fcc981937fe92fd41994008610a351d90ea3acaa Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 7 Oct 2021 16:57:43 +0200 Subject: [PATCH 063/117] Debugger: Expand macros in "Additional Startup Commands" Fixes: QTCREATORBUG-26382 Change-Id: I43cc2ac9451dbb44bcc12ed8555535fb8b4e437e Reviewed-by: Artem Sokolovskii Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggerengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index debdcaafdd4..514f778f909 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1891,7 +1891,7 @@ QString DebuggerEngine::nativeStartupCommands() const return !trimmed.isEmpty() && !trimmed.startsWith('#'); }); - return lines.join('\n'); + return expand(lines.join('\n')); } Perspective *DebuggerEngine::perspective() const From f36ab584511edcb8fe524e9313e8ac7696996ef3 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Thu, 14 Oct 2021 16:59:44 +0300 Subject: [PATCH 064/117] Android: Align api and revision columns to the right Change-Id: Ib6e0d1e0b6922cfe5b90e320b25b2dce2dcaba14 Reviewed-by: Alessandro Portale --- src/plugins/android/androidsdkmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp index 0fd6321fd00..2d0e7af83e4 100644 --- a/src/plugins/android/androidsdkmodel.cpp +++ b/src/plugins/android/androidsdkmodel.cpp @@ -220,7 +220,7 @@ QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const } if (role == Qt::TextAlignmentRole && index.column() == packageRevisionColumn) - return Qt::AlignHCenter; + return Qt::AlignRight; if (role == Qt::ToolTipRole) return QString("%1 - (%2)").arg(p->descriptionText()).arg(p->sdkStylePath()); From f91b64f645ee76340e48ea75a8e3b9028ae14997 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 14 Oct 2021 11:39:35 +0300 Subject: [PATCH 065/117] QmlDesigner: Add item library icons for Component, Loader, and Repeater Task-number: QDS-5063 Change-Id: If397b89e22b626c210bffece0e66041b043f2897 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Bot --- .../qtquickplugin/images/component-icon.png | Bin 0 -> 626 bytes .../qtquickplugin/images/component-icon16.png | Bin 0 -> 438 bytes .../qtquickplugin/images/component-icon@2x.png | Bin 0 -> 1107 bytes .../qtquickplugin/images/loader-icon.png | Bin 0 -> 321 bytes .../qtquickplugin/images/loader-icon16.png | Bin 0 -> 222 bytes .../qtquickplugin/images/loader-icon@2x.png | Bin 0 -> 483 bytes .../qtquickplugin/images/repeater-icon.png | Bin 0 -> 191 bytes .../qtquickplugin/images/repeater-icon16.png | Bin 0 -> 187 bytes .../qtquickplugin/images/repeater-icon@2x.png | Bin 0 -> 196 bytes .../qmldesigner/qtquickplugin/qtquickplugin.qrc | 9 +++++++++ .../qmldesigner/qtquickplugin/quick.metainfo | 12 ++++++------ 11 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/component-icon.png create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/component-icon16.png create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/component-icon@2x.png create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/loader-icon.png create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/loader-icon16.png create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/loader-icon@2x.png create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/repeater-icon.png create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/repeater-icon16.png create mode 100644 src/plugins/qmldesigner/qtquickplugin/images/repeater-icon@2x.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/component-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/component-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9c7df42bc7019f9de572461dbe9011eae259c898 GIT binary patch literal 626 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuL8EInNuLp(a)PIb%>4isqH z|CZZp!-m|kf7b)Yd_fU5M*&C2 zDN0QbOb@5qibV7AE{%)0JdDng7 z?SkUm+_mQm=LGjXo)Z@pWi`=5#jd}vZ=a;3WaaJKw|C!SnBuxbTWi;pc{O7E# zQF}kFe)ROy&c`=%zB%5gE^rU6R+0$Q5i|Z+ap%Ui+??C@R^?tXn>Ky=_OP&UpPeyg z>t0J8;NI4C+QG@?UDpYp1NS-SFyCvx*kiaXZvE!S`zF4@w;BHTy#M+5@PRcQ6{~Ks z?@8PJyq!rZbnAyo*@n9u?_OI?2)&y4V6lA7{!fSAJ>dEvD#151e`;<9Yhsq&d0Agy z-&#o-nVP)FFjJNd6MfX~ry9-7{#{iNwDOAo1E;M~Z)0L&Y+hTOJDRkyqNt|kkF(X> mI>U+cDz4tW8_V>ATj$_`Z~ilw${83K7(8A5T-G@yGywn)Nh#R? literal 0 HcmV?d00001 diff --git a/src/plugins/qmldesigner/qtquickplugin/images/component-icon16.png b/src/plugins/qmldesigner/qtquickplugin/images/component-icon16.png new file mode 100644 index 0000000000000000000000000000000000000000..99941541c6fbb6416e052edc2b4a272e351cce85 GIT binary patch literal 438 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7Ydu{YLo9mtPBQdnb`)sc zzdOcNo%d$+Q+Ja887)|rL!+6Q5qxNiiW73XLhRY_tSA)IO znSY3F@cW-XG02Z$`IqC?vbqKbzWXW&-_l^-J~3s|$tTHQdKrW|kG$@8+Zm$ed;Rs- u(Bp;MqSl5L7AAh&wIO7}=i<-d^RKG5{k$Lez?Ff4fx*+&&t;ucLK6TeJiWUB literal 0 HcmV?d00001 diff --git a/src/plugins/qmldesigner/qtquickplugin/images/component-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/component-icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f66349a63b2f3688c2c3c99a226497b3b81dc268 GIT binary patch literal 1107 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_PXzdcxH2#>tN?>wzkaP) zvEs*%AD=&eeg^|9R;+mc{ykWJ#q;OSSFC`N4<9~!^5h9b975i|e;>ktkf%tXOg2;DHq@R$RPzam9)iyTD-2o;?s{D^{#Hbm$O-4VKvjVQ<~K6~b7wXc0v5 zwr$%WB9kUfTCrlqrcImL+S*pESkcqlGiAyY2pdAKUcI`hscFTE71O3oTd`ur1y1F`u;`oI4 z;*w&B6hy?FTWC821H+_}AirP+MrLL=oUa5K7#LT0x;Tb-biTbB8h+S7g6+YBcYKH2Zx=`yKxsx0}%KqGik;{#)s1LX_agiU3bmoT(h z9k5`_xb`XYS!0;S1N%O~-|@$_x9wP|q$}aC8{CsS?ZrFK-j;EVWnh9@BN;tA+zg^|C)$8@j@*}w{e%@^GG(L0ln%XM6JMre5 zbh4K?{L7xg&~S0S+}pLaVTbPoC^)^$=1n_ep{>KmerWOvcaBSi2@@N5naTt@B&1?qoivs2T|UI*E{$xS(+x-W~P@nc(vf5{QPhC=T=nH8QT&(q}NSZA@EIh=0Ez`(%Z M>FVdQ&MBb@04PL6&;S4c literal 0 HcmV?d00001 diff --git a/src/plugins/qmldesigner/qtquickplugin/images/loader-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..29082eacf168fe10d04985852949f49af51625a0 GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8NNDlA`ab;j&SV3cu?|uIb z0|SFXNswPK0~0eFpMa=>nx28ZTUcg8W9!5j3pQ*%c>TtMN3Y+1`yCchIER6OA=lHz zF+?NyZl60}gMtX_e9@zE8>ZL)57wF}adcC`%bbRp9~f_Vc6i2uP_xB$xyfq_eUGu`n9zVrq h^sPUnD}P9sJKaz;)Gw)$w zF7fWWtSwp7w4br1?BF-H8OI+htP5Yjw#`9x<{cYHjQ4;TI4Z9h;C+SW;To(m7@RlBJur?LU6z z+KmTKUwrub?fb94@(DQw3=9mLJzX3_JdP(PEZ{OQVP|X%^z7uHG)<+$zh=<_lSL;S zm?jvTho`H!GB>Z{W9O4BG&sOvXBH=;C8@x8$g^dsz|_MY%^MgJ8x}QI7#NvO;9@B3 XnDE-}{YM)H1_lOCS3j3^P6pTnzgdwM5cv TUY})PU|{fc^>bP0l+XkKm3Tid literal 0 HcmV?d00001 diff --git a/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon16.png b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon16.png new file mode 100644 index 0000000000000000000000000000000000000000..775a57a38c3c305f559ffbfbb7435a48d6635f00 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd7G?$phPQVgfdq5|d_r6q7#LO%4Gx?sJj1}i zz*iFF7tCM~&@f}ggJ-WkeE$05-?cw!+6)W~`kpS1Aso@kPhO`b{5ySM(wP%KWsfBM zZcQlYZk9Bc*m>h%&-92Z2bMnQIvLDd%*LSlPD8LL&DxBCfq}u()z4*}Q$iB}$wN^- literal 0 HcmV?d00001 diff --git a/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bb541b671122f8150b2a0c22788a4a85cd5a103f GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-7G?$phNU`BwlFX-$OZU>xH2#>tiTPdr+>W8 zz`(#+666=mFk!>p2hTr!`}6TZ-&+O-1|Lrs#}JFt$q5NFI#~@23?59@2x?-usvyCv z_3!`#qYszCu?tf&3L6=|3rR3*P1N9EJk(}z%;2--OCgJ9mUM-_wyP(&wdc69WiI7s aShcC==fYV(J~A*cFnGH9xvXimages/animated-image-icon.png images/animated-image-icon@2x.png images/animated-image-icon16.png + images/component-icon.png + images/component-icon@2x.png + images/component-icon16.png + images/repeater-icon.png + images/repeater-icon@2x.png + images/repeater-icon16.png + images/loader-icon.png + images/loader-icon@2x.png + images/loader-icon16.png diff --git a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo index 019be099732..851d457cdc3 100644 --- a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo +++ b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo @@ -434,7 +434,7 @@ MetaInfo { Type { name: "QtQml.Component" - icon: ":/qtquickplugin/images/item-icon16.png" + icon: ":/qtquickplugin/images/component-icon16.png" Hints { canBeDroppedInNavigator: true @@ -444,19 +444,19 @@ MetaInfo { ItemLibraryEntry { name: "Component" category: "e.Qt Quick - Component" - libraryIcon: ":/qtquickplugin/images/item-icon.png" + libraryIcon: ":/qtquickplugin/images/component-icon.png" version: "2.0" } } Type { name: "QtQuick.Loader" - icon: ":/qtquickplugin/images/item-icon16.png" + icon: ":/qtquickplugin/images/loader-icon16.png" ItemLibraryEntry { name: "Loader" category: "e.Qt Quick - Component" - libraryIcon: ":/qtquickplugin/images/item-icon.png" + libraryIcon: ":/qtquickplugin/images/loader-icon.png" version: "2.0" Property { name: "width"; type: "int"; value: 200; } Property { name: "height"; type: "int"; value: 200; } @@ -465,7 +465,7 @@ MetaInfo { Type { name: "QtQuick.Repeater" - icon: ":/qtquickplugin/images/item-icon16.png" + icon: ":/qtquickplugin/images/repeater-icon16.png" Hints { canBeDroppedInFormEditor: false @@ -475,7 +475,7 @@ MetaInfo { ItemLibraryEntry { name: "Repeater" category: "e.Qt Quick - Component" - libraryIcon: ":/qtquickplugin/images/item-icon.png" + libraryIcon: ":/qtquickplugin/images/repeater-icon.png" version: "2.0" } } From 9c86e6746fb82d6244cc2fc565d5f730c67f8106 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 11 Oct 2021 18:12:07 +0200 Subject: [PATCH 066/117] CppEditor: Prefer target flags from the build system The build system has in-depth knowledge of how to build the project and is therefore a much more reliable source of information about the concrete target triple than what we extracted generically from the toolchain. Fixes: QTCREATORBUG-25615 Change-Id: I820f8dd99da3832326308510a50aa7cbb4aa8fdb Reviewed-by: Alessandro Portale --- .../cppeditor/compileroptionsbuilder.cpp | 35 ++++++++++++------- .../cppeditor/compileroptionsbuilder.h | 1 + 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/plugins/cppeditor/compileroptionsbuilder.cpp b/src/plugins/cppeditor/compileroptionsbuilder.cpp index 14921c51ebc..09f71fa93fd 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder.cpp +++ b/src/plugins/cppeditor/compileroptionsbuilder.cpp @@ -123,7 +123,7 @@ CompilerOptionsBuilder::~CompilerOptionsBuilder() = default; QStringList CompilerOptionsBuilder::build(ProjectFile::Kind fileKind, UsePrecompiledHeaders usePrecompiledHeaders) { - m_options.clear(); + reset(); evaluateCompilerFlags(); if (fileKind == ProjectFile::CHeader || fileKind == ProjectFile::CSource) { @@ -251,9 +251,12 @@ void CompilerOptionsBuilder::addWordWidth() void CompilerOptionsBuilder::addTargetTriple() { + const QString target = m_explicitTarget.isEmpty() + ? m_projectPart.toolChainTargetTriple : m_explicitTarget; + // Only "--target=" style is accepted in both g++ and cl driver modes. - if (!m_projectPart.toolChainTargetTriple.isEmpty()) - add("--target=" + m_projectPart.toolChainTargetTriple); + if (!target.isEmpty()) + add("--target=" + target); } void CompilerOptionsBuilder::addExtraCodeModelFlags() @@ -771,6 +774,7 @@ void CompilerOptionsBuilder::undefineClangVersionMacrosForMsvc() void CompilerOptionsBuilder::reset() { m_options.clear(); + m_explicitTarget.clear(); } // Some example command lines for a "Qt Console Application": @@ -786,12 +790,18 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() const Id toolChain = m_projectPart.toolchainType; bool containsDriverMode = false; bool skipNext = false; - const QStringList allFlags = m_projectPart.compilerFlags + m_projectPart.extraCodeModelFlags; + bool nextIsTarget = false; + const QStringList allFlags = m_projectPart.extraCodeModelFlags + m_projectPart.compilerFlags; for (const QString &option : allFlags) { if (skipNext) { skipNext = false; continue; } + if (nextIsTarget) { + nextIsTarget = false; + m_explicitTarget = option; + continue; + } if (userBlackList.contains(option)) continue; @@ -812,14 +822,15 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() continue; } - // As we always set the target explicitly, filter out target args. - if (!m_projectPart.toolChainTargetTriple.isEmpty()) { - if (option.startsWith("--target=")) - continue; - if (option == "-target") { - skipNext = true; - continue; - } + // An explicit target triple from the build system takes precedence over the generic one + // from the toolchain. + if (option.startsWith("--target=")) { + m_explicitTarget = option.mid(9); + continue; + } + if (option == "-target") { + nextIsTarget = true; + continue; } if (option == includeUserPathOption || option == includeSystemPathOption diff --git a/src/plugins/cppeditor/compileroptionsbuilder.h b/src/plugins/cppeditor/compileroptionsbuilder.h index 0211d58a188..cc75e984bed 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder.h +++ b/src/plugins/cppeditor/compileroptionsbuilder.h @@ -122,6 +122,7 @@ private: } m_compilerFlags; QStringList m_options; + QString m_explicitTarget; bool m_clStyle = false; }; From 9234bc369b1f9250e2b83a08c543e47ded2846f8 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 14 Oct 2021 14:23:05 +0200 Subject: [PATCH 067/117] ClangCodeModel: Fix highlighting of user-defined string literals ... with clangd. Task-number: QTCREATORBUG-26425 Change-Id: I805ed5a68a990528ef20dcac015591a2a600066b Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index db8f275b4df..20cb497095f 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -3006,6 +3006,8 @@ void ExtraHighlightingResultsCollector::setResultPosFromRange(HighlightingResult void ExtraHighlightingResultsCollector::collectFromNode(const AstNode &node) { + if (node.kind() == "UserDefinedLiteral") + return; if (node.kind().endsWith("Literal")) { HighlightingResult result; result.useTextSyles = true; From c4256a9a2b4bf92f84baea0435d414373493af46 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 13 Oct 2021 17:18:07 +0200 Subject: [PATCH 068/117] CppEditor: Squash three copies of the "is in comment or string" check Change-Id: Id6c4e35ae2d3b3031e5c95ea04f5b971bef58389 Reviewed-by: David Schulz --- .../clangcompletionassistprocessor.cpp | 37 ++-------------- src/plugins/clangcodemodel/clangdclient.cpp | 42 ++----------------- src/plugins/cppeditor/cppcompletionassist.cpp | 34 +-------------- src/plugins/cppeditor/cpptoolsreuse.cpp | 40 +++++++++++++++++- src/plugins/cppeditor/cpptoolsreuse.h | 6 +++ 5 files changed, 53 insertions(+), 106 deletions(-) diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index af964f5be95..1d924f8b2da 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -44,10 +45,7 @@ #include #include -#include -#include #include -#include #include @@ -431,37 +429,8 @@ bool ClangCompletionAssistProcessor::accepts() const if (pos - startOfName >= TextEditorSettings::completionSettings().m_characterThreshold) { const QChar firstCharacter = m_interface->characterAt(startOfName); if (firstCharacter.isLetter() || firstCharacter == QLatin1Char('_')) { - // Finally check that we're not inside a comment or string (code copied from startOfOperator) - QTextCursor tc(m_interface->textDocument()); - tc.setPosition(pos); - - SimpleLexer tokenize; - LanguageFeatures lf = tokenize.languageFeatures(); - lf.qtMocRunEnabled = true; - lf.objCEnabled = true; - tokenize.setLanguageFeatures(lf); - tokenize.setSkipComments(false); - const Tokens &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block())); - const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); - const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); - - if (!tk.isComment() && !tk.isLiteral()) { - return true; - } else if (tk.isLiteral() - && tokens.size() == 3 - && tokens.at(0).kind() == T_POUND - && tokens.at(1).kind() == T_IDENTIFIER) { - const QString &line = tc.block().text(); - const Token &idToken = tokens.at(1); - QStringView identifier = Utils::midView(line, - idToken.utf16charsBegin(), - idToken.utf16chars()); - if (identifier == QLatin1String("include") - || identifier == QLatin1String("include_next") - || (m_interface->objcEnabled() && identifier == QLatin1String("import"))) { - return true; - } - } + return !CppEditor::isInCommentOrString(m_interface.data(), + m_interface->languageFeatures()); } } } diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 20cb497095f..d5b63ec1e8f 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -35,11 +35,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -98,13 +96,6 @@ static Q_LOGGING_CATEGORY(clangdLogHighlight, "qtc.clangcodemodel.clangd.highlig static Q_LOGGING_CATEGORY(clangdLogTiming, "qtc.clangcodemodel.clangd.timing", QtWarningMsg); static QString indexingToken() { return "backgroundIndexProgress"; } -static QStringView subView(const QString &s, qsizetype start) -{ - if (start < 0 || start > s.length()) - return {}; - return QStringView(s).mid(start); -} - static QStringView subViewLen(const QString &s, qsizetype start, qsizetype length) { if (start < 0 || length < 0 || start + length > s.length()) @@ -2646,36 +2637,9 @@ bool ClangdClient::ClangdCompletionAssistProvider::isContinuationChar(const QCha bool ClangdClient::ClangdCompletionAssistProvider::isInCommentOrString( const AssistInterface *interface) const { - QTextCursor tc(interface->textDocument()); - tc.setPosition(interface->position()); - - SimpleLexer tokenize; - tokenize.setSkipComments(false); - const Tokens &tokens = tokenize(tc.block().text(), - BackwardsScanner::previousBlockState(tc.block())); - const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); - const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); - - if (tk.isComment()) - return true; - if (!tk.isLiteral()) - return false; - if (tokens.size() == 3 && tokens.at(0).kind() == T_POUND - && tokens.at(1).kind() == T_IDENTIFIER) { - const QString &line = tc.block().text(); - const Token &idToken = tokens.at(1); - QStringView identifier = idToken.utf16charsEnd() > line.size() - ? subView(line, idToken.utf16charsBegin()) - : subViewLen(line, idToken.utf16charsBegin(), - idToken.utf16chars()); - if (identifier == QLatin1String("include") - || identifier == QLatin1String("include_next") - || (CppEditor::ProjectFile::isObjC(interface->filePath().toString()) - && identifier == QLatin1String("import"))) { - return false; - } - } - return true; + LanguageFeatures features = LanguageFeatures::defaultFeatures(); + features.objCEnabled = CppEditor::ProjectFile::isObjC(interface->filePath().toString()); + return CppEditor::isInCommentOrString(interface, features); } void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, diff --git a/src/plugins/cppeditor/cppcompletionassist.cpp b/src/plugins/cppeditor/cppcompletionassist.cpp index cd2c70b78c3..ee04a159570 100644 --- a/src/plugins/cppeditor/cppcompletionassist.cpp +++ b/src/plugins/cppeditor/cppcompletionassist.cpp @@ -858,38 +858,8 @@ bool InternalCppCompletionAssistProcessor::accepts() const if (pos - startOfName >= TextEditorSettings::completionSettings().m_characterThreshold) { const QChar firstCharacter = m_interface->characterAt(startOfName); if (isValidFirstIdentifierChar(firstCharacter)) { - // Finally check that we're not inside a comment or string (code copied from startOfOperator) - QTextCursor tc(m_interface->textDocument()); - tc.setPosition(pos); - - SimpleLexer tokenize; - tokenize.setLanguageFeatures(m_interface->languageFeatures()); - tokenize.setSkipComments(false); - - const Tokens &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block())); - const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); - const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); - - if (!tk.isComment() && !tk.isLiteral()) { - return true; - } else if (tk.isLiteral() - && tokens.size() == 3 - && tokens.at(0).kind() == T_POUND - && tokens.at(1).kind() == T_IDENTIFIER) { - const QString &line = tc.block().text(); - const Token &idToken = tokens.at(1); - QStringView identifier = idToken.utf16charsEnd() > line.size() - ? QStringView(line).mid( - idToken.utf16charsBegin()) - : QStringView(line) - .mid(idToken.utf16charsBegin(), - idToken.utf16chars()); - if (identifier == QLatin1String("include") - || identifier == QLatin1String("include_next") - || (m_interface->languageFeatures().objCEnabled && identifier == QLatin1String("import"))) { - return true; - } - } + return !isInCommentOrString(m_interface.data(), + m_interface->languageFeatures()); } } } diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp index 15a1bea88a1..04f679824ae 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.cpp +++ b/src/plugins/cppeditor/cpptoolsreuse.cpp @@ -39,11 +39,15 @@ #include #include #include +#include #include -#include +#include #include +#include +#include #include +#include #include #include @@ -300,6 +304,40 @@ const Macro *findCanonicalMacro(const QTextCursor &cursor, Document::Ptr documen return nullptr; } +bool isInCommentOrString(const TextEditor::AssistInterface *interface, + CPlusPlus::LanguageFeatures features) +{ + QTextCursor tc(interface->textDocument()); + tc.setPosition(interface->position()); + + SimpleLexer tokenize; + features.qtMocRunEnabled = true; + tokenize.setLanguageFeatures(features); + tokenize.setSkipComments(false); + const Tokens &tokens = tokenize(tc.block().text(), + BackwardsScanner::previousBlockState(tc.block())); + const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); + const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); + + if (tk.isComment()) + return true; + if (!tk.isLiteral()) + return false; + if (tokens.size() == 3 && tokens.at(0).kind() == T_POUND + && tokens.at(1).kind() == T_IDENTIFIER) { + const QString &line = tc.block().text(); + const Token &idToken = tokens.at(1); + QStringView identifier = Utils::midView(line, idToken.utf16charsBegin(), + idToken.utf16chars()); + if (identifier == QLatin1String("include") + || identifier == QLatin1String("include_next") + || (features.objCEnabled && identifier == QLatin1String("import"))) { + return false; + } + } + return true; +} + CppCodeModelSettings *codeModelSettings() { return Internal::CppEditorPlugin::instance()->codeModelSettings(); diff --git a/src/plugins/cppeditor/cpptoolsreuse.h b/src/plugins/cppeditor/cpptoolsreuse.h index b3fd7a274b4..e7023b7be78 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.h +++ b/src/plugins/cppeditor/cpptoolsreuse.h @@ -35,6 +35,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QChar; @@ -48,6 +49,8 @@ class Symbol; class LookupContext; } // namespace CPlusPlus +namespace TextEditor { class AssistInterface; } + namespace CppEditor { class CppRefactoringFile; class ProjectInfo; @@ -71,6 +74,9 @@ bool CPPEDITOR_EXPORT isOwnershipRAIIType(CPlusPlus::Symbol *symbol, const CPlusPlus::Macro CPPEDITOR_EXPORT *findCanonicalMacro(const QTextCursor &cursor, CPlusPlus::Document::Ptr document); +bool CPPEDITOR_EXPORT isInCommentOrString(const TextEditor::AssistInterface *interface, + CPlusPlus::LanguageFeatures features); + enum class CacheUsage { ReadWrite, ReadOnly }; QString CPPEDITOR_EXPORT correspondingHeaderOrSource(const QString &fileName, bool *wasHeader = nullptr, From fe4a033a44b09eb04d526ff79c77fe6bea43e119 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 12 Oct 2021 17:45:26 +0200 Subject: [PATCH 069/117] ClangCodeModel: Improve completion with clangd Namely, do not duplicate parts of the to-be-completed item (including parentheses) that already exist at the cursor position. The code is taken from ClangAssistProposalItem; I had left it off in the original implementation, because I mistakenly assumed that clangd would handle this situation itself. Change-Id: I216f5d507a54db90cd23af2fadb26060dbc4a735 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 51 ++++++++++++--------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index d5b63ec1e8f..d8b98a0a2d0 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -2651,35 +2651,27 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, if (!edit) return; - const auto kind = static_cast( - item.kind().value_or(CompletionItemKind::Text)); - if (kind != CompletionItemKind::Function && kind != CompletionItemKind::Method - && kind != CompletionItemKind::Constructor) { - applyTextEdit(manipulator, *edit, true); - return; - } - const QString rawInsertText = edit->newText(); const int firstParenOffset = rawInsertText.indexOf('('); const int lastParenOffset = rawInsertText.lastIndexOf(')'); - if (firstParenOffset == -1 || lastParenOffset == -1) { - applyTextEdit(manipulator, *edit, true); - return; - } - const QString detail = item.detail().value_or(QString()); const CompletionSettings &completionSettings = TextEditorSettings::completionSettings(); QString textToBeInserted = rawInsertText.left(firstParenOffset); QString extraCharacters; + int extraLength = 0; int cursorOffset = 0; bool setAutoCompleteSkipPos = false; - const QTextDocument * const doc = manipulator.textCursorAt( - manipulator.currentPosition()).document(); + int currentPos = manipulator.currentPosition(); + const QTextDocument * const doc = manipulator.textCursorAt(currentPos).document(); const Range range = edit->range(); const int rangeStart = range.start().toPositionInDocument(doc); - const int rangeLength = range.end().toPositionInDocument(doc) - rangeStart; - if (completionSettings.m_autoInsertBrackets) { + const auto kind = static_cast( + item.kind().value_or(CompletionItemKind::Text)); + const bool isFunctionLike = kind == CompletionItemKind::Function + || kind == CompletionItemKind::Method || kind == CompletionItemKind::Constructor + || (firstParenOffset != -1 && lastParenOffset != -1); + if (isFunctionLike && completionSettings.m_autoInsertBrackets) { // If the user typed the opening parenthesis, they'll likely also type the closing one, // in which case it would be annoying if we put the cursor after the already automatically // inserted closing parenthesis. @@ -2707,7 +2699,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, // If the function doesn't return anything, automatically place the semicolon, // unless we're doing a scope completion (then it might be function definition). - const QChar characterAtCursor = manipulator.characterAt(manipulator.currentPosition()); + const QChar characterAtCursor = manipulator.characterAt(currentPos); bool endWithSemicolon = typedChar == ';'; const QChar semicolon = typedChar.isNull() ? QLatin1Char(';') : typedChar; if (endWithSemicolon && characterAtCursor == semicolon) { @@ -2723,7 +2715,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, typedChar = {}; } } else { - const QChar lookAhead = manipulator.characterAt(manipulator.currentPosition() + 1); + const QChar lookAhead = manipulator.characterAt(currentPos + 1); if (MatchingText::shouldInsertMatchingText(lookAhead)) { extraCharacters += ')'; --cursorOffset; @@ -2745,9 +2737,26 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, --cursorOffset; } - textToBeInserted += extraCharacters; + // Avoid inserting characters that are already there + QTextCursor cursor = manipulator.textCursorAt(rangeStart); + cursor.movePosition(QTextCursor::EndOfWord); + const QString textAfterCursor = manipulator.textAt(currentPos, cursor.position() - currentPos); + if (textToBeInserted != textAfterCursor + && textToBeInserted.indexOf(textAfterCursor, currentPos - rangeStart) >= 0) { + currentPos = cursor.position(); + } + for (int i = 0; i < extraCharacters.length(); ++i) { + const QChar a = extraCharacters.at(i); + const QChar b = manipulator.characterAt(currentPos + i); + if (a == b) + ++extraLength; + else + break; + } - const bool isReplaced = manipulator.replace(rangeStart, rangeLength, textToBeInserted); + textToBeInserted += extraCharacters; + const int length = currentPos - rangeStart + extraLength; + const bool isReplaced = manipulator.replace(rangeStart, length, textToBeInserted); manipulator.setCursorPosition(rangeStart + textToBeInserted.length()); if (isReplaced) { if (cursorOffset) From a0a1495d208b835f0e3a3eeb8c6c9860fb51d640 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 15 Oct 2021 07:02:40 +0200 Subject: [PATCH 070/117] Update qbs submodule To HEAD of 1.21. Change-Id: I748ee0bb38bcdd692316c5379946fe9d4d72d7ff Reviewed-by: Christian Kandeler --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index a35ff56175c..966689ab499 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit a35ff56175cc8c993b54bb1d92ff71ba4532fc88 +Subproject commit 966689ab499725cb7e7ab1157043b968a1a39e60 From 40f863b9cf108425eac235e2a5142e62de2f1453 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 15 Oct 2021 10:40:02 +0200 Subject: [PATCH 071/117] LanguageClient: Allow to log to console rather than message window And make use of that in ClangdClient. When I get a slowdown while typing, it is usually accompanied by the clangd message "Request cancelled because the document was modified" occurring in the message window, often many times in a row. I'd like to find out whether writing to the message window itself is a contributing factor to the slowdown. Change-Id: Iff7c459af0aed27d22366b9aade573f51eb5dbc7 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 1 + src/plugins/languageclient/client.cpp | 9 ++++++++- src/plugins/languageclient/client.h | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index d8b98a0a2d0..34eb06791ae 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -1081,6 +1081,7 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir) "text/x-c++hdr", "text/x-c++src", "text/x-objc++src", "text/x-objcsrc"}; setSupportedLanguage(langFilter); setActivateDocumentAutomatically(true); + setLogTarget(LogTarget::Console); setCompletionAssistProvider(new ClangdCompletionAssistProvider(this)); if (!project) { QJsonObject initOptions; diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 5f2b44d5e91..b177f82c520 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -1133,7 +1133,14 @@ void Client::handleMessage(const BaseMessage &message) void Client::log(const QString &message) const { - Core::MessageManager::writeFlashing(QString("LanguageClient %1: %2").arg(name(), message)); + switch (m_logTarget) { + case LogTarget::Ui: + Core::MessageManager::writeFlashing(QString("LanguageClient %1: %2").arg(name(), message)); + break; + case LogTarget::Console: + qCDebug(LOGLSPCLIENT) << message; + break; + } } const ServerCapabilities &Client::capabilities() const diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index bf06359ef41..59f23599a49 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -189,6 +189,8 @@ public: void setCompletionAssistProvider(LanguageClientCompletionAssistProvider *provider); // logging + enum class LogTarget { Console, Ui }; + void setLogTarget(LogTarget target) { m_logTarget = target; } void log(const QString &message) const; template void log(const LanguageServerProtocol::ResponseError &responseError) const @@ -288,6 +290,7 @@ private: QString m_serverName; QString m_serverVersion; LanguageServerProtocol::SymbolStringifier m_symbolStringifier; + LogTarget m_logTarget = LogTarget::Ui; bool m_locatorsEnabled = true; bool m_autoRequestCodeActions = true; }; From cab210ad369a87523000e2565eb07646f827de01 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 13 Oct 2021 19:54:42 +0200 Subject: [PATCH 072/117] WebAssembly: Call emrun.py directly instead of via the wrapper script From now on do on Linux and macOS what was already done on Windows in order to launch a WebAssembly program: Directly call the emrun.py python script instead of indirectly via the wrapper shell script. The wrapper was too fragile. Also, this change consolidates the code paths on the three host platforms a bit. Fixes: QTCREATORBUG-25905 Fixes: QTCREATORBUG-26189 Change-Id: If79567e4dc688de460b38daa479becb53d3c5f03 Reviewed-by: Juha Vuolle Reviewed-by: Christian Stenger --- .../webassemblyrunconfiguration.cpp | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/plugins/webassembly/webassemblyrunconfiguration.cpp b/src/plugins/webassembly/webassemblyrunconfiguration.cpp index 82d7f8d9a53..123887caf7b 100644 --- a/src/plugins/webassembly/webassemblyrunconfiguration.cpp +++ b/src/plugins/webassembly/webassemblyrunconfiguration.cpp @@ -40,25 +40,32 @@ using namespace Utils; namespace WebAssembly { namespace Internal { +static FilePath pythonInterpreter(const Environment &env) +{ + const QString emsdkPythonEnvVarKey("EMSDK_PYTHON"); + if (env.hasKey(emsdkPythonEnvVarKey)) + return FilePath::fromUserInput(env.value(emsdkPythonEnvVarKey)); + + // FIXME: Centralize addPythonsFromPath() from the Python plugin and use that + for (const char *interpreterCandidate : {"python3", "python", "python2"}) { + const FilePath interpereter = env.searchInPath(QLatin1String(interpreterCandidate)); + if (interpereter.isExecutableFile()) + return interpereter; + } + return {}; +} + static CommandLine emrunCommand(Target *target, const QString &browser, const QString &port) { if (BuildConfiguration *bc = target->activeBuildConfiguration()) { - const QFileInfo emrun = bc->environment().searchInPath("emrun").toFileInfo(); - auto html = bc->buildDirectory().pathAppended(target->project()->displayName() + ".html"); + const Environment env = bc->environment(); + const FilePath emrun = env.searchInPath("emrun"); + const FilePath emrunPy = emrun.absolutePath().pathAppended(emrun.baseName() + ".py"); + const FilePath html = + bc->buildDirectory().pathAppended(target->project()->displayName() + ".html"); - // On Windows, we need to use the python interpreter (it comes with the emsdk) to ensure - // that the web server is killed when the application is stopped in Qt Creator. - // On Non-windows, we prefer using the shell script, because that knows how to find the - // right python (not part of emsdk). The shell script stays attached to the server process. - const FilePath interpreter = HostOsInfo::isWindowsHost() - ? FilePath::fromUserInput(bc->environment().value("EMSDK_PYTHON")) - : bc->environment().searchInPath("sh"); - const QString emrunLaunchScript = HostOsInfo::isWindowsHost() - ? emrun.absolutePath() + "/" + emrun.baseName() + ".py" - : emrun.absoluteFilePath(); - - return CommandLine(interpreter, { - emrunLaunchScript, + return CommandLine(pythonInterpreter(env), { + emrunPy.path(), "--browser", browser, "--port", port, "--no_emrun_detect", From dafc32d8e21b3febc7fa228dd85abb7ed2e588a7 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 14 Oct 2021 09:02:26 +0300 Subject: [PATCH 073/117] GDB: Do not pass regular expressions to set substitute-path Change-Id: If647e2d12b261ba2137c952640dfdb3a984fcfbf Reviewed-by: hjk --- src/plugins/debugger/gdb/gdbengine.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index c87ec179116..6b1a53ab96d 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3796,8 +3796,11 @@ static SourcePathMap mergeStartParametersSourcePathMap(const DebuggerRunParamete { // Do not overwrite user settings. SourcePathMap rc = sp.sourcePathMap; - for (auto it = in.constBegin(), end = in.constEnd(); it != end; ++it) - rc.insert(it.key(), it.value()); + for (auto it = in.constBegin(), end = in.constEnd(); it != end; ++it) { + // Entries that start with parenthesis are handled in CppDebuggerEngine::validateRunParameters + if (!it.key().startsWith('(')) + rc.insert(it.key(), it.value()); + } return rc; } From 52f9db1ae064bfe70c87f9e03c272da25924ff6c Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 14 Oct 2021 09:05:38 +0300 Subject: [PATCH 074/117] GDB: Expand macros on substitute paths Change-Id: Ifb7a7f007a7c46045d7c315c02c8309f0a599dbc Reviewed-by: hjk --- src/plugins/debugger/gdb/gdbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 6b1a53ab96d..b5494c9f024 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3799,7 +3799,7 @@ static SourcePathMap mergeStartParametersSourcePathMap(const DebuggerRunParamete for (auto it = in.constBegin(), end = in.constEnd(); it != end; ++it) { // Entries that start with parenthesis are handled in CppDebuggerEngine::validateRunParameters if (!it.key().startsWith('(')) - rc.insert(it.key(), it.value()); + rc.insert(it.key(), sp.macroExpander->expand(it.value())); } return rc; } From 097efa58ba1579773e50d0fea579328ebf8c2cb5 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 15 Oct 2021 11:31:13 +0200 Subject: [PATCH 075/117] ClangCodeModel: Add some clangd completion logging Change-Id: I35dea3ad2815683181eb5dfbe1ea7d985037f55c Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 34eb06791ae..719c9e3352d 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -94,6 +94,8 @@ static Q_LOGGING_CATEGORY(clangdLogServer, "qtc.clangcodemodel.clangd.server", Q static Q_LOGGING_CATEGORY(clangdLogAst, "qtc.clangcodemodel.clangd.ast", QtWarningMsg); static Q_LOGGING_CATEGORY(clangdLogHighlight, "qtc.clangcodemodel.clangd.highlight", QtWarningMsg); static Q_LOGGING_CATEGORY(clangdLogTiming, "qtc.clangcodemodel.clangd.timing", QtWarningMsg); +static Q_LOGGING_CATEGORY(clangdLogCompletion, "qtc.clangcodemodel.clangd.completion", + QtWarningMsg); static QString indexingToken() { return "backgroundIndexProgress"; } static QStringView subViewLen(const QString &s, qsizetype start, qsizetype length) @@ -2582,19 +2584,26 @@ ClangdClient::ClangdCompletionAssistProvider::ClangdCompletionAssistProvider(Cla IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor( const AssistInterface *interface) const { + qCDebug(clangdLogCompletion) << "completion processor requested for" << interface->filePath(); + qCDebug(clangdLogCompletion) << "text before cursor is" + << interface->textAt(interface->position(), -10); + qCDebug(clangdLogCompletion) << "text after cursor is" + << interface->textAt(interface->position(), 10); ClangCompletionContextAnalyzer contextAnalyzer(interface->textDocument(), interface->position(), false, {}); contextAnalyzer.analyze(); switch (contextAnalyzer.completionAction()) { case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: - qCDebug(clangdLog) << "completion changed to function hint"; + qCDebug(clangdLogCompletion) << "creating function hint processor"; return new ClangdFunctionHintProcessor(m_client); case ClangCompletionContextAnalyzer::CompleteDoxygenKeyword: + qCDebug(clangdLogCompletion) << "creating doxygen processor"; return new CustomAssistProcessor(m_client, contextAnalyzer.positionForProposal(), contextAnalyzer.completionOperator(), CustomAssistMode::Doxygen); case ClangCompletionContextAnalyzer::CompletePreprocessorDirective: + qCDebug(clangdLogCompletion) << "creating macro processor"; return new CustomAssistProcessor(m_client, contextAnalyzer.positionForProposal(), contextAnalyzer.completionOperator(), @@ -2605,6 +2614,8 @@ IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor( const QString snippetsGroup = contextAnalyzer.addSnippets() && !isInCommentOrString(interface) ? CppEditor::Constants::CPP_SNIPPETS_GROUP_ID : QString(); + qCDebug(clangdLogCompletion) << "creating proper completion processor" + << (snippetsGroup.isEmpty() ? "without" : "with") << "snippets"; return new ClangdCompletionAssistProcessor(m_client, snippetsGroup); } @@ -2625,6 +2636,7 @@ bool ClangdClient::ClangdCompletionAssistProvider::isActivationCharSequence(cons // contexts, such as '(', '<' or '/'. switch (kind) { case T_DOT: case T_COLON_COLON: case T_ARROW: case T_DOT_STAR: case T_ARROW_STAR: case T_POUND: + qCDebug(clangdLogCompletion) << "detected" << sequence << "as activation char sequence"; return true; } return false; From 5f1e6b15bf6d2af24ab4b5b500e6ba36a79600e7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 15 Oct 2021 12:55:12 +0200 Subject: [PATCH 076/117] LanguageClient: Only present snippets in addition to proper completions Prevents spurious suggestions of snippets and is in line with what we did for C++ so far. Change-Id: I54e11b6567f00938f9aa7dfe771547471e87439c Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientcompletionassist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index ca38029dc13..3eec6cbbd9d 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -425,7 +425,7 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse( items = Utils::get>(*result); } auto proposalItems = generateCompletionItems(items); - if (!m_snippetsGroup.isEmpty()) { + if (!proposalItems.isEmpty() && !m_snippetsGroup.isEmpty()) { proposalItems << TextEditor::SnippetAssistCollector( m_snippetsGroup, QIcon(":/texteditor/images/snippet.png")).collect(); } From a746510937d259a20a785a508741e1d659456dfe Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 15 Oct 2021 16:49:12 +0300 Subject: [PATCH 077/117] StudioWelcome: Fix studio welcome plugin crash crash introduced by ea8400a9ffd365300fbbb25abec8f71e9c6a016a Change-Id: I7302e71076634caaf68dd52cf61451110629ce0d Reviewed-by: Miikka Heikkinen --- src/plugins/studiowelcome/studiowelcomeplugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index ae5bbf29fab..d1195675624 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -340,6 +340,7 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro qmlRegisterType("projectmodel", 1, 0, "ProjectModel"); qmlRegisterType("usagestatistics", 1, 0, "UsageStatisticModel"); + m_welcomeMode = new WelcomeMode; m_removeSplashTimer.setSingleShot(true); m_removeSplashTimer.setInterval(15000); From 13bca02801536124c833b02ce199fd7013e288b4 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 14 Oct 2021 15:25:24 +0200 Subject: [PATCH 078/117] ProjectExplorer: Clean paths in OutputLineParser::absoluteFilePath() Fixes: QTCREATORBUG-26422 Change-Id: I350bbd076007647c4de21db08f2b034d654eb812 Reviewed-by: hjk --- src/libs/utils/outputformatter.cpp | 4 +++- src/plugins/projectexplorer/gccparser.cpp | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp index 4efcae76468..cf6930cbe57 100644 --- a/src/libs/utils/outputformatter.cpp +++ b/src/libs/utils/outputformatter.cpp @@ -136,8 +136,10 @@ bool OutputLineParser::demoteErrorsToWarnings() const FilePath OutputLineParser::absoluteFilePath(const FilePath &filePath) const { - if (filePath.isEmpty() || filePath.toFileInfo().isAbsolute()) + if (filePath.isEmpty()) return filePath; + if (filePath.toFileInfo().isAbsolute()) + return filePath.cleanPath(); FilePaths candidates; for (const FilePath &dir : searchDirectories()) { FilePath candidate = dir.pathAppended(filePath.toString()); diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp index 6479240c2b0..30ebe45bf82 100644 --- a/src/plugins/projectexplorer/gccparser.cpp +++ b/src/plugins/projectexplorer/gccparser.cpp @@ -1367,6 +1367,14 @@ void ProjectExplorerPlugin::testGccOutputParsers_data() CompileTask(Task::Error, ".pch/Qt6Core5Compat: No such file or directory", ".pch/Qt6Core5Compat"), CompileTask(Task::Warning, "-Wformat-security ignored without -Wformat [-Wformat-security]")} << QString(); + + QTest::newRow("clean path") + << QString("/home/tim/path/to/sources/./and/more.h:15:22: error: blubb") + << OutputParserTester::STDERR + << QString() << QString() + << Tasks{CompileTask(Task::Error, "blubb", "/home/tim/path/to/sources/and/more.h", + 15, 22)} + << QString(); } void ProjectExplorerPlugin::testGccOutputParsers() From 10a6497146f736f71dec22a6800442b1340e56c6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 11 Oct 2021 23:06:51 +0200 Subject: [PATCH 079/117] Sync mimeglobpattern sources with Qt The optimization for VdrPattern and AnimPattern speeds up loading of Qt6 project with further ~200 ms. Change-Id: I28451a627d6c509854907736da48efcf68a86019 Reviewed-by: hjk --- src/libs/utils/mimetypes/mimeglobpattern.cpp | 100 +++++++++++++------ src/libs/utils/mimetypes/mimeglobpattern_p.h | 32 ++++-- 2 files changed, 94 insertions(+), 38 deletions(-) diff --git a/src/libs/utils/mimetypes/mimeglobpattern.cpp b/src/libs/utils/mimetypes/mimeglobpattern.cpp index d595a17b7bc..ae0899dd0ed 100644 --- a/src/libs/utils/mimetypes/mimeglobpattern.cpp +++ b/src/libs/utils/mimetypes/mimeglobpattern.cpp @@ -83,6 +83,39 @@ void MimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QS } } +MimeGlobPattern::PatternType MimeGlobPattern::detectPatternType(const QString &pattern) const +{ + const int patternLength = pattern.length(); + if (!patternLength) + return OtherPattern; + + const bool starCount = pattern.count(QLatin1Char('*')) == 1; + const bool hasSquareBracket = pattern.indexOf(QLatin1Char('[')) != -1; + const bool hasQuestionMark = pattern.indexOf(QLatin1Char('?')) != -1; + + if (!hasSquareBracket && !hasQuestionMark) { + if (starCount == 1) { + // Patterns like "*~", "*.extension" + if (pattern.at(0) == QLatin1Char('*')) + return SuffixPattern; + // Patterns like "README*" (well this is currently the only one like that...) + if (pattern.at(patternLength - 1) == QLatin1Char('*')) + return PrefixPattern; + } + // Names without any wildcards like "README" + if (starCount == 0) + return LiteralPattern; + } + + if (pattern == QLatin1String("[0-9][0-9][0-9].vdr")) + return VdrPattern; + + if (pattern == QLatin1String("*.anim[1-9j]")) + return AnimPattern; + + return OtherPattern; +} + /*! \internal \class MimeGlobPattern @@ -92,54 +125,63 @@ void MimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QS \sa MimeType, MimeDatabase, MimeMagicRuleMatcher, MimeMagicRule */ -bool MimeGlobPattern::matchFileName(const QString &inputFilename) const +bool MimeGlobPattern::matchFileName(const QString &inputFileName) const { // "Applications MUST match globs case-insensitively, except when the case-sensitive // attribute is set to true." // The constructor takes care of putting case-insensitive patterns in lowercase. - const QString filename = m_caseSensitivity == Qt::CaseInsensitive ? inputFilename.toLower() : inputFilename; + const QString fileName = m_caseSensitivity == Qt::CaseInsensitive + ? inputFileName.toLower() : inputFileName; - const int pattern_len = m_pattern.length(); - if (!pattern_len) + const int patternLength = m_pattern.length(); + if (!patternLength) return false; - const int len = filename.length(); + const int fileNameLength = fileName.length(); - // Patterns like "*~", "*.extension" - if (m_pattern[0] == QLatin1Char('*') && m_openingSquareBracketPos == -1 && m_starCount == 1) { - if (len + 1 < pattern_len) + switch (m_patternType) { + case SuffixPattern: { + if (fileNameLength + 1 < patternLength) return false; - const QChar *c1 = m_pattern.unicode() + pattern_len - 1; - const QChar *c2 = filename.unicode() + len - 1; + const QChar *c1 = m_pattern.unicode() + patternLength - 1; + const QChar *c2 = fileName.unicode() + fileNameLength - 1; int cnt = 1; - while (cnt < pattern_len && *c1-- == *c2--) + while (cnt < patternLength && *c1-- == *c2--) ++cnt; - return cnt == pattern_len; + return cnt == patternLength; } - - // Patterns like "README*" (well this is currently the only one like that...) - if (m_starCount == 1 && m_pattern.at(pattern_len - 1) == QLatin1Char('*')) { - if (len + 1 < pattern_len) + case PrefixPattern: { + if (fileNameLength + 1 < patternLength) return false; - if (m_pattern.at(0) == QLatin1Char('*')) - return filename.indexOf(QStringView(m_pattern).mid(1, pattern_len - 2)) != -1; const QChar *c1 = m_pattern.unicode(); - const QChar *c2 = filename.unicode(); + const QChar *c2 = fileName.unicode(); int cnt = 1; - while (cnt < pattern_len && *c1++ == *c2++) + while (cnt < patternLength && *c1++ == *c2++) ++cnt; - return cnt == pattern_len; + return cnt == patternLength; } - - // Names without any wildcards like "README" - if (m_openingSquareBracketPos == -1 && m_starCount == 0 && m_questionMarkPos == -1) - return (m_pattern == filename); - - // Other (quite rare) patterns, like "*.anim[1-9j]": use slow but correct method - const QRegularExpression rx(QRegularExpression::anchoredPattern( + case LiteralPattern: + return (m_pattern == fileName); + case VdrPattern: // "[0-9][0-9][0-9].vdr" case + return fileNameLength == 7 + && fileName.at(0).isDigit() && fileName.at(1).isDigit() && fileName.at(2).isDigit() + && QStringView{fileName}.mid(3, 4) == QLatin1String(".vdr"); + case AnimPattern: { // "*.anim[1-9j]" case + if (fileNameLength < 6) + return false; + const QChar lastChar = fileName.at(fileNameLength - 1); + const bool lastCharOK = (lastChar.isDigit() && lastChar != QLatin1Char('0')) + || lastChar == QLatin1Char('j'); + return lastCharOK && QStringView{fileName}.mid(fileNameLength - 6, 5) == QLatin1String(".anim"); + } + case OtherPattern: + // Other fallback patterns: slow but correct method + const QRegularExpression rx(QRegularExpression::anchoredPattern( QRegularExpression::wildcardToRegularExpression(m_pattern))); - return rx.match(filename).hasMatch(); + return rx.match(fileName).hasMatch(); + } + return false; } static bool isFastPattern(const QString &pattern) diff --git a/src/libs/utils/mimetypes/mimeglobpattern_p.h b/src/libs/utils/mimetypes/mimeglobpattern_p.h index 28fa01551c4..990a5b07d2f 100644 --- a/src/libs/utils/mimetypes/mimeglobpattern_p.h +++ b/src/libs/utils/mimetypes/mimeglobpattern_p.h @@ -79,15 +79,21 @@ public: m_pattern(s == Qt::CaseInsensitive ? thePattern.toLower() : thePattern), m_mimeType(theMimeType), m_weight(theWeight), - m_starCount(m_pattern.count(QLatin1Char('*'))), - m_openingSquareBracketPos(m_pattern.indexOf(QLatin1Char('['))), - m_questionMarkPos(m_pattern.indexOf(QLatin1Char('?'))), - m_caseSensitivity(s) + m_caseSensitivity(s), + m_patternType(detectPatternType(m_pattern)) { } - ~MimeGlobPattern() {} - bool matchFileName(const QString &filename) const; + void swap(MimeGlobPattern &other) noexcept + { + qSwap(m_pattern, other.m_pattern); + qSwap(m_mimeType, other.m_mimeType); + qSwap(m_weight, other.m_weight); + qSwap(m_caseSensitivity, other.m_caseSensitivity); + qSwap(m_patternType, other.m_patternType); + } + + bool matchFileName(const QString &inputFileName) const; inline const QString &pattern() const { return m_pattern; } inline unsigned weight() const { return m_weight; } @@ -95,13 +101,21 @@ public: inline bool isCaseSensitive() const { return m_caseSensitivity == Qt::CaseSensitive; } private: + enum PatternType { + SuffixPattern, + PrefixPattern, + LiteralPattern, + VdrPattern, // special handling for "[0-9][0-9][0-9].vdr" pattern + AnimPattern, // special handling for "*.anim[1-9j]" pattern + OtherPattern + }; + PatternType detectPatternType(const QString &pattern) const; + QString m_pattern; QString m_mimeType; int m_weight; - int m_starCount; - int m_openingSquareBracketPos; - int m_questionMarkPos; Qt::CaseSensitivity m_caseSensitivity; + PatternType m_patternType; }; class MimeGlobPatternList : public QList From 3cde937ea19da0d65ceb80f9c14225d03fa8bd15 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 13 Oct 2021 18:52:55 +0200 Subject: [PATCH 080/117] QmlDesigner: Fix casting of .bool Font.bold is of type .bool and we did not recognize it. Task-number: QDS-5274 Change-Id: I420dc62e1f1dc8b9e22a2c0678c882a72d8b0907 Reviewed-by: Aleksei German Reviewed-by: Qt CI Bot --- src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index 33693210a99..97ff30850ff 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -1505,6 +1505,8 @@ QVariant NodeMetaInfo::propertyCastedValue(const PropertyName &propertyName, con return variant.toFloat(); } else if (typeName == ".int") { return variant.toInt(); + } else if (typeName == ".bool") { + return variant.toBool(); } else if (copyVariant.convert(typeId)) { return copyVariant; } From badc1f855175d6b6d1916443b69f010c0b4a6fa6 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 14 Oct 2021 09:02:03 +0300 Subject: [PATCH 081/117] Debugger: Use correct macroExpander when substituting regexp Change-Id: I1d17063044b0e0e52b055a3e53b214f311cf6008 Reviewed-by: hjk --- src/plugins/debugger/debuggerengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 514f778f909..87d52ad74b1 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -2827,7 +2827,7 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) globalRegExpSourceMap.reserve(sourcePathMap.size()); for (auto it = sourcePathMap.begin(), end = sourcePathMap.end(); it != end; ++it) { if (it.key().startsWith('(')) { - const QString expanded = Utils::globalMacroExpander()->expand(it.value()); + const QString expanded = rp.macroExpander->expand(it.value()); if (!expanded.isEmpty()) globalRegExpSourceMap.push_back( qMakePair(QRegularExpression(it.key()), expanded)); From 73fa76f776a2a9fbc3ea4f77a799afb35fc5d87c Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 5 Oct 2021 15:50:41 +0200 Subject: [PATCH 082/117] Doc: Remove info about Qt Quick Designer plugin from Qt Creator Manual Fixes: QTCREATORBUG-26321 Change-Id: I8738cbdc56d6469a4d133b17741871787e0cba9f Reviewed-by: Thomas Hartmann Reviewed-by: Alessandro Portale --- .../config/qtcreator-project.qdocconf | 17 +-- .../qtcreator-extraimages.qdocconf | 12 +-- .../images/qmldesigner-backends-add.png | Bin 6976 -> 0 bytes doc/qtcreator/images/qmldesigner-backends.png | Bin 3740 -> 0 bytes .../images/qmldesigner-new-project.png | Bin 18298 -> 17167 bytes .../images/qtcreator-live-preview.png | Bin 103145 -> 46355 bytes .../qtcreator-new-qt-quick-project-wizard.png | Bin 33979 -> 17426 bytes .../images/qtcreator-new-subproject.png | Bin 15964 -> 17167 bytes .../images/qtcreator-qt-quick-editors.png | Bin 118018 -> 0 bytes .../src/debugger/qtquick-debugging.qdoc | 7 +- .../src/editors/creator-code-syntax.qdoc | 22 ++-- .../src/editors/creator-quick-fixes.qdoc | 6 +- .../external-resources-qds.qdoc | 43 ++++++++ .../external-resources.qdoc | 8 ++ .../src/howto/creator-keyboard-shortcuts.qdoc | 4 +- .../src/howto/creator-only/qtcreator-faq.qdoc | 2 +- .../src/howto/creator-telemetry.qdoc | 66 +----------- .../creator-commercial-overview.qdoc | 3 +- .../creator-only/creator-design-overview.qdoc | 11 +- .../overview/creator-only/creator-issues.qdoc | 11 -- .../creator-only/creator-overview.qdoc | 4 +- .../creator-only/creator-tutorials.qdoc | 2 +- doc/qtcreator/src/qtcreator-toc.qdoc | 100 +----------------- .../creator-only/qtquick-app-development.qdoc | 83 +++++---------- .../qtquick-connection-editor-backend.qdoc | 73 ------------- .../qtquick-iso-icon-browser.qdoc | 77 -------------- .../qtquick-from-qmlproject-to-pro.qdoc | 27 ++--- .../qtquick/qtquick-live-preview-desktop.qdoc | 15 +-- .../src/qtquick/qtquick-live-preview.qdoc | 7 +- .../qtquick/qtquick-modules-with-plugins.qdoc | 70 ++++++------ .../src/qtquick/qtquick-toolbars.qdoc | 18 +++- .../src/qtquick/qtquick-ui-forms.qdoc | 19 ++-- .../creator-file-system-view.qdoc | 2 + .../creator-open-documents-view.qdoc | 9 +- .../user-interface/creator-projects-view.qdoc | 10 +- .../src/user-interface/creator-ui.qdoc | 5 - .../src/user-interface/creator-views.qdoc | 6 +- .../widgets/creator-faq-qtdesigner.qdocinc | 8 +- .../src/widgets/qtdesigner-overview.qdoc | 2 +- .../components}/qtquick-animation-types.qdoc | 0 .../src/components}/qtquick-buttons.qdoc | 0 .../qtquick-component-context-menu.qdocinc | 0 .../qtquick-component-instances.qdoc | 0 .../qtquick-components-custom.qdoc | 0 .../src/components}/qtquick-components.qdoc | 0 .../src/components}/qtquick-controls.qdoc | 0 .../src/components}/qtquick-data-models.qdoc | 0 .../src/components}/qtquick-images.qdoc | 0 .../qtquick-pathview-editor.qdocinc | 0 .../src/components}/qtquick-positioning.qdoc | 0 .../qtquick-preset-components.qdoc | 0 .../src/components}/qtquick-shapes.qdoc | 0 .../src/components}/qtquick-text.qdoc | 0 .../qtquick-user-interaction-methods.qdoc | 0 .../qtdesignstudio-simulation-overview.qdoc | 9 +- .../qtquick-animation-overview.qdoc | 0 .../src/overviews}/qtquick-annotations.qdoc | 0 .../overviews}/qtquick-creating-ui-logic.qdoc | 0 .../src/overviews}/qtquick-export.qdoc | 0 .../src/overviews}/qtquick-fonts.qdoc | 0 .../src/overviews}/qtquick-motion-design.qdoc | 0 .../qtquick-optimizing-designs.qdoc | 0 .../overviews}/qtquick-placeholder-data.qdoc | 7 +- .../qtquick-production-quality-animation.qdoc | 0 .../src/overviews}/qtquick-prototyping.qdoc | 0 .../src/overviews}/qtquick-uis.qdoc | 0 .../src/overviews/studio-crashpad.qdoc | 59 +++++++++++ .../src/overviews/studio-user-feedback.qdoc | 52 +++++++++ .../src/qtdesignstudio-packaging.qdoc | 2 +- .../qtdesignstudio-optimized-3d-scenes.qdoc | 0 .../views}/creator-logical-operators.qdocinc | 0 .../src/views}/qtquick-adding-dynamics.qdoc | 0 .../qtquick-connection-editor-bindings.qdoc | 0 .../qtquick-connection-editor-properties.qdoc | 0 .../qtquick-connection-editor-signals.qdoc | 0 .../src/views}/qtquick-connection-editor.qdoc | 0 .../src/views}/qtquick-connection-view.qdoc | 0 .../src/views}/qtquick-curve-editor.qdoc | 0 .../src/views}/qtquick-designer.qdoc | 0 .../views}/qtquick-easing-curve-editor.qdoc | 0 .../src/views}/qtquick-form-editor.qdoc | 0 .../src/views}/qtquick-library.qdoc | 0 .../src/views}/qtquick-navigator.qdoc | 0 .../src/views}/qtquick-properties-view.qdoc | 0 .../src/views}/qtquick-properties.qdoc | 0 .../src/views}/qtquick-states-view.qdoc | 0 .../src/views}/qtquick-states.qdoc | 0 .../src/views}/qtquick-text-editor.qdoc | 0 .../src/views}/qtquick-timeline-view.qdoc | 0 .../src/views}/qtquick-timeline.qdoc | 0 .../src/views}/qtquick-transition-editor.qdoc | 0 91 files changed, 336 insertions(+), 542 deletions(-) delete mode 100644 doc/qtcreator/images/qmldesigner-backends-add.png delete mode 100644 doc/qtcreator/images/qmldesigner-backends.png delete mode 100644 doc/qtcreator/images/qtcreator-qt-quick-editors.png create mode 100644 doc/qtcreator/src/external-resources/external-resources-qds.qdoc delete mode 100644 doc/qtcreator/src/qtquick/creator-only/qtquick-connection-editor-backend.qdoc delete mode 100644 doc/qtcreator/src/qtquick/creator-only/qtquick-iso-icon-browser.qdoc rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/components}/qtquick-animation-types.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/components}/qtquick-buttons.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/components}/qtquick-component-context-menu.qdocinc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-component-instances.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-components-custom.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/components}/qtquick-components.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-controls.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-data-models.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-images.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-pathview-editor.qdocinc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/components}/qtquick-positioning.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-preset-components.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-shapes.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-text.qdoc (100%) rename doc/{qtcreator/src/qtquick/library => qtdesignstudio/src/components}/qtquick-user-interaction-methods.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtdesignstudio-simulation-overview.qdoc (92%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-animation-overview.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-annotations.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-creating-ui-logic.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-export.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-fonts.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-motion-design.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-optimizing-designs.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-placeholder-data.qdoc (95%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-production-quality-animation.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-prototyping.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/overviews}/qtquick-uis.qdoc (100%) create mode 100644 doc/qtdesignstudio/src/overviews/studio-crashpad.qdoc create mode 100644 doc/qtdesignstudio/src/overviews/studio-user-feedback.qdoc rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/qtquick3d-editor}/qtdesignstudio-optimized-3d-scenes.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/creator-logical-operators.qdocinc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-adding-dynamics.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-connection-editor-bindings.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-connection-editor-properties.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-connection-editor-signals.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-connection-editor.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-connection-view.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-curve-editor.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-designer.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-easing-curve-editor.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-form-editor.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-library.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-navigator.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-properties-view.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-properties.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-states-view.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-states.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-text-editor.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-timeline-view.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-timeline.qdoc (100%) rename doc/{qtcreator/src/qtquick => qtdesignstudio/src/views}/qtquick-transition-editor.qdoc (100%) diff --git a/doc/qtcreator/config/qtcreator-project.qdocconf b/doc/qtcreator/config/qtcreator-project.qdocconf index 096548517da..ed35b4e41ee 100644 --- a/doc/qtcreator/config/qtcreator-project.qdocconf +++ b/doc/qtcreator/config/qtcreator-project.qdocconf @@ -12,11 +12,9 @@ ignorewords += \ MinGW headerdirs = -sourcedirs = ../src \ - ../../qtdesignstudio/src/qtquick3d-editor +sourcedirs = ../src imagedirs = ../images \ - ../../qtdesignstudio/images \ ../../../src/libs/qmleditorwidgets/images \ ../../../src/libs/utils/images \ ../../../src/plugins/android/images \ @@ -27,14 +25,6 @@ imagedirs = ../images \ ../../../src/plugins/diffeditor/images \ ../../../src/plugins/help/images \ ../../../src/plugins/projectexplorer/images \ - ../../../src/plugins/qmldesigner/components/componentcore/images \ - ../../../src/plugins/qmldesigner/components/edit3d/images \ - ../../../src/plugins/qmldesigner/components/formeditor \ - ../../../src/plugins/qmldesigner/components/navigator \ - ../../../src/plugins/qmldesigner/components/timelineeditor/images \ - ../../../src/plugins/qmldesigner/componentsplugin/images \ - ../../../src/plugins/qmldesigner/qmlpreviewplugin/images \ - ../../../src/plugins/qmldesigner/qtquickplugin/images \ ../../../src/plugins/scxmleditor/common/images \ ../../../src/plugins/texteditor/images \ ../../../src/plugins/valgrind/images \ @@ -50,17 +40,12 @@ depends += qtandroidextras\ qtcmake \ qtcore \ qtqml \ - qtqmlmodels \ qtquick \ qmake \ qtdesigner \ qtdoc \ - qtgraphicaleffects \ qtgui \ qthelp \ - qtquick3d \ - qtquickcontrols \ - qtquickextras \ qtquicktimeline \ qtlinguist \ qtscxml \ diff --git a/doc/qtcreator/images/extraimages/qtcreator-extraimages.qdocconf b/doc/qtcreator/images/extraimages/qtcreator-extraimages.qdocconf index 9cd8ce979e8..af81e511928 100644 --- a/doc/qtcreator/images/extraimages/qtcreator-extraimages.qdocconf +++ b/doc/qtcreator/images/extraimages/qtcreator-extraimages.qdocconf @@ -1,12 +1,2 @@ {HTML.extraimages,qhp.QtCreator.extraFiles} += \ - images/commercial.png \ - images/RfEYO-5Mw6s.jpg \ - images/yOUdg1o2KJM.jpg \ - images/DVWd_xMMgvg.jpg \ - images/Ed8WS03C-Vk.jpg \ - images/UfvA04CIXv0.jpg \ - images/FzmLuRHQXaw.jpg \ - images/pEETxSxYazg.jpg \ - images/V3Po15bNErw.jpg \ - images/bMXeeQw6BYs.jpg \ - images/u3kZJjlk3CY.jpg + images/commercial.png diff --git a/doc/qtcreator/images/qmldesigner-backends-add.png b/doc/qtcreator/images/qmldesigner-backends-add.png deleted file mode 100644 index a11ad9923c6112fc8125c5165064c8f0b1750a6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6976 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 diff --git a/doc/qtcreator/images/qmldesigner-backends.png b/doc/qtcreator/images/qmldesigner-backends.png deleted file mode 100644 index f5eb6c26bc98456405184c2fdcef7728fe195ff3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3740 zcmeAS@N?(olHy`uVBq!ia0y~yV0^~Fz_6QxiGhK^e%dNl1_r)lPZ!6Kid%2*-tU%u zDtX}J9o8zrh*^7YtO}f*5u)_ynD$-{r97sjsitNpTNmhVoAvD26ppqn30pFzO7tcP zxU9&1$=}-W%;^s^my_T@?Z4@7tkciU{Cw_=b#Yqx`FB6R{`@46{`}1O^t64?XQroJ zkNqC=KQ2erZ@yivHp3f^-4@d~F$S2WGBc#+*Z+C+X6f$#fA>FePyBO=yM9RygKXv3 ztKs&4J{;y}tNHbE`Pa;I^X=x_SRk+fVb~SMmM%{m|OKKg+BA z|9snK|9|SHM%Kjt|NhSYXY%~h)6?a53f(_Go~j-G>axwpBf^P)8kyO(9v`0Z{eJ!b zm&@nNEq%lN+M6{yeEY?I`8m;cHSf+_`*?KU;nlzYZTZ-0a^&CX|B?T$au=?Z zZTmj2!tO>)GE0Qay_(Nwr~Uf=>gwvRAJ5xw#Ju!=eZaBWZ%|*E2eUW`QQfnFKxwriK_FrEo z?!3Ei(WmXFKW&bGvYqv&L(JymuXTIR?{7S`%DrCn?fy@d245HM|8M@qGq3)4yqrA~ z_X+LwdxX3mR0aO|^?JSf^7_|nx0~IP(6p%gQ!(Sgz3TV8|Jfd2SNG7Uu3Y(U)0xdX z^)^e{Z1Jk{d&6x~64)g0I(gGhw(eKn#>FL`yRRPeXcrBYve>)t?7yuKue)XK{cD&w zQ#mQ( z@{f;?r^nab+_&rN*RT2eeyY8T?++@wn_75VQ9ndGxhVDeah;=6o_lHSKHatIzUslF z&69R!?wxsgbCGrSrxyRu`AvMbzt+eXeLDJq$#ccl&wQMz%-koG`)!I|URwI-_=N{{ zWp5%b9}!J`-ooDL-Y+M+bI~4op*RK3|IcJ6T|5;RxysbdZ0#F0$9~_Nw&L*;KelJ? zt*ot8T)(EeZvTe3mm5{?KR^BJ`rbN^Yl@b&W$k!MPkmb?FJz^%aB-0S6KlIVpRd|(TGq3)s}drzdt7W^Tkl?@@wMpm zhSGU)`QI*{dRX`P_qp`z&ebXx*RS7q{(H@fE}r>r`~IGPBRlEV?D{FZI!p_F`1p8_ ze%+dVebU$WVpCb`Ye&P8$+-?@HcymXQx$K;(YPsy*AEiGYzV3EUciY9fxA)z? zzen@VU(zc-abV6|-RP;Q2iyL5-<)#yt=EhW^R#VuddzBse;e?JmepK)bK&2cl3T}= zPV-hz-lVyE?y@XZ`FO2`zrtT$k3XI~Sy?+Y;_wOkkgVS?CcWA9t?lcZ1)CQC5mmO% z$*OwS&P-HxKjpn<%8#9!UKa;{Tcc$iyGv#Di5FV3hMUSa9$j^|&HL(~ zi{0|#i`lf-|5$zamio1bjKG%{_OEnNEzeTk?BlJkdh5YMwXf};^yf_qoqWG=s^n^Q zpVUm>bnmQt8&fiKdM9QrjNV)nzbJlhjZ#oqjLLVnZ_8ixo^M-R*?xH$*PoA~@21$U zJ*C(CCh5|Yu)3UeU6-`w|6Hkk+o_cI+}i4^u1{`OQJ?P_qm8leJ}td^f5)qZ*>CRi zyQ%rlICW{(xoJ=KB%i!g5hZl7VDCA&AIn#IBFlx&G=+)Z&>e{OtW~u6X_B_?;b-&px z^!@RQD{Dngai;SBlKuJRrP0pKn^w2}7rS+Piq+bFdF$Idb5kyzkIv~avHf^j|Bk0d z^@<)obC#>eOJ~nW4cfh@F!jFGDnp}3Eiae7`LgHniAxbvVqX@!#J&yeo!Gd0@w&2` zTNhU;^xkKmVmn>`r>Pyon~Y1J{$^!zZWVuQ_Tk6IrOcZr=Qcgj&Qs3gSXKT(dFtFb zsY$!{aHf`5{)srTrS8xc-L*CPVYAD1BBj22*B!l4bbay9kB=8DG~BiN(v8}crf%DA zNG=T7@71j5vu)A6w%D1iNeHB~m{uPgsGwua2`Z@%Vt zr)XRAoDgRSFk@)g#F+4IYOVK?Q>VPvy)h8zf4}KVwABL%h6B&0#@giPq%X-mzEy_7 zVezJJKM!l=-ztxz_!t(fJ#}w)`TO(iE&rbvy}M=*(8D8KvU1borz$Tufz{6LN_}bo zH6G-g;8kz_XfAr*!eGFBiVaD83NOQgoSx>ZS3^A~XzyHuXPSL3o=hmjR`c1 zi9#0SJa^}Z=CgL~ek=B6uP(ikT_BylNIw0gM6YG|;mxN0PCqJV%sSVd;q{=U*jh2Q zKXtwO%w0#Jeo~e29<^!kdzMSH}tu20P*&E5=vNGQ<-P8UlzWDpxYyXzc zS2K;j22R=A+y3m#)W$8{*~-=tPpucfSuAZ{cjEY${(zM>^A9LWZ{MUH9iOteWRcsa z7w=2oZ_YU7{@QY-*oTWVK7CJ3(k)*0=2u^M(Nw$d8r4kgYj=v z_2%vR3^q&uxP-&XCKg>srRDg@hJ}{tsxQ4WZJ9Km>NTVE zQ+{tNF26hWTrSoB$%e1z?>+I1*=NJ1lQ7p-Fg2a|Xs!QJt~IALEDdHlZ{ywh>aBOE zmalr&=@V6clP>qiJeZ?d{iJXE{OT!tFSoB%e|;pk;`PVHZ)A5asyd!l&^&)d>n@%% z?(4d4x9e){uG{Z)Q&#Wiw&MOx>JM9`&GU}5-uZB?$l|1vb#>4wJ=?A|Tb-lUnrw77 z3ruydo_iw5Ry|fqxp@7XC-0^eUoCqV`0bqhwugy3OzRefR*4zb{MpcPUS56qn^Ufn z`)GUS{8N|P-%bvc&bHL8!Vtes!= zGv7;3cc;|#NZs(_qe|M=>#b%UlI1m} z_WalPtpZMGTtIaP2y>hga{^<>n@${x8qpBUlFGetMd9_s$N5SXeAGY&IQdvKCB1v? zFvDlvldeszGxoHFSv%Y;a=qzvVM5H=otyOE-xMt___=qR>zzLdW*6TDUq5{~Q8C+m zxwxGEhRjV*j;x&c{Q9ZeGv_R=ZG0+Q|Dnj{(}9)E%Eks++0kVM^PHY#daP56Ox+%z zeDdV3GnWcC-ktLI-pspKIk)NbT`H}st-QZ(ZD(>JSlu$Gn>P>4W9NT&tNfY6f2S_* zmv+_Xjvp?a`u)VI6;)GX=jME0Y5Z~3bpN%g*Ju2lp=rJE-0Asd`MGue0rxgMoX2N( z*6T+`vX*!Djjflig`&!ll$rNFS9dYk+DDbO{tWcwEE?WO}oGLO+KufT6#I5l}^*BI+}lZ`bMye;%+`XwQ^RW)Reo|-M1=kZd|L||58)= z%KN3PeG#{o9W}iD_WiwBzqNhSK-Odie*3_-dGRLWnbV{@PIl|g$~kh#e9@b2YuDyP zq$cydtJ|=q^T?&BvbBpXUfnh*4$RCuVZ(d!s)(sum%3T@+|_S>O8FTAonaa+|*BY)?jtsnM#O}?AW zFXznZ=v<^4etE^4gVM=&?;jIQGJCYHy}$f-u>0|+UhDoG+9luwPkNwa2g2Z_$CApe z2*NEl!cx~WF{H7aVq<`mf{^kTR8oTrLIws_L@~OD>fFgCowQEFnGH9xvXoZ diff --git a/doc/qtcreator/images/qmldesigner-new-project.png b/doc/qtcreator/images/qmldesigner-new-project.png index 8554f7af892bd5cda9283120f005afc4c871f8ba..7bab02c38f1d93290c41e70fc149146e637490ad 100644 GIT binary patch literal 17167 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

&z5TD}~`u;T-K_j68>B+!e)NFD~C>HvQkpgYka+ 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 ~XaJ@UA%rLA?*01Xn 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 diff --git a/doc/qtcreator/images/qtcreator-new-qt-quick-project-wizard.png b/doc/qtcreator/images/qtcreator-new-qt-quick-project-wizard.png index a2a5bf396fce2eb8a1654f4369a6299e6a755d0f..d9d7509a8ad1dca09b2fd77fcdc254064f2a2edd 100644 GIT binary patch literal 17426 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 literal 33979 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%0DXo_w@MT|8iE!7N3-L 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 diff --git a/doc/qtcreator/images/qtcreator-new-subproject.png b/doc/qtcreator/images/qtcreator-new-subproject.png index e65a09bee68854be3eb78e87b3342911204507cc..7bab02c38f1d93290c41e70fc149146e637490ad 100644 GIT binary patch literal 17167 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 diff --git a/doc/qtcreator/images/qtcreator-qt-quick-editors.png b/doc/qtcreator/images/qtcreator-qt-quick-editors.png deleted file mode 100644 index 2d06ea84b40d715cea7b01f6f5aa7cedff8c03fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118018 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%0D4u^Kx%xa}(^ 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 diff --git a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc index bdc1bda67e1..05b89ebab89 100644 --- a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc +++ b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc @@ -244,7 +244,12 @@ You can change property values temporarily, without editing the source, and view the results in the running application. You can change the property - values permanently in the \uicontrol Properties view in the Design mode. + values permanently in + \if defined(qtcreator) + code. + \else + the \l Properties view. + \endif \section1 Applying QML Changes at Runtime diff --git a/doc/qtcreator/src/editors/creator-code-syntax.qdoc b/doc/qtcreator/src/editors/creator-code-syntax.qdoc index 1afc4566472..7ba22031edc 100644 --- a/doc/qtcreator/src/editors/creator-code-syntax.qdoc +++ b/doc/qtcreator/src/editors/creator-code-syntax.qdoc @@ -433,45 +433,44 @@ \row \li M203 \li Warning - \li Imperative code is not supported in the Design mode + \li Imperative code is not supported in \QDS \li \row \li M204 \li Warning - \li This QML type is not supported in the Design mode + \li This QML type is not supported in \QDS \li \row \li M205 \li Warning - \li Reference to parent QML type cannot be resolved correctly by the - Design mode + \li Reference to parent QML type cannot be resolved correctly by \QDS \li \row \li M206 \li Warning \li This visual property binding cannot be evaluated in the local - context and might not show up in Design mode as expected + context and might not show up in \QDS as expected \li \row \li M207 \li Warning - \li Design mode only supports states in the root QML type + \li \QDS only supports states in the root QML type \li \row \li M208 \li Error - \li This id might be ambiguous and is not supported in the Design mode. + \li This id might be ambiguous and is not supported in \QDS. \li \row \li M209 \li Error - \li This type (type name) is not supported as a root element in the - Design mode. + \li This type (type name) is not supported as a root element in + \QDS. \li \row @@ -691,8 +690,7 @@ instead of Qt Quick 2}. You can see the error message when you move the mouse pointer over code that - \QC underlines in the code editor or when you open a QML file in the Design - mode. + \QC underlines in the code editor or when you open a QML file in \QDS. To reset the code model, select \uicontrol Tools > \uicontrol {QML/JS} > \uicontrol {Reset Code Model}. @@ -700,7 +698,7 @@ \if defined(qtcreator) If this does not help, try changing the QML emulation layer to the one that was built with the same Qt version as the one selected in the build and run - kit. For more information, see \l{Running QML Modules in Design Mode}. + kit. \endif \section1 Inspecting QML and JavaScript diff --git a/doc/qtcreator/src/editors/creator-quick-fixes.qdoc b/doc/qtcreator/src/editors/creator-quick-fixes.qdoc index efe8ecc058a..0a063ee3ba7 100644 --- a/doc/qtcreator/src/editors/creator-quick-fixes.qdoc +++ b/doc/qtcreator/src/editors/creator-quick-fixes.qdoc @@ -869,8 +869,10 @@ \image qtcreator-move-component-into-separate-file.png - \li QML type name. This action is also available in the - \uicontrol {Form Editor} in the Design mode. + \li QML type name. + \if defined(qtdesignstudio) + This action is also available in \l {Form Editor}. + \endif \row \li Split Initializer \li Reformats a one-line type into a multi-line type. For example, diff --git a/doc/qtcreator/src/external-resources/external-resources-qds.qdoc b/doc/qtcreator/src/external-resources/external-resources-qds.qdoc new file mode 100644 index 00000000000..48adc0a98f0 --- /dev/null +++ b/doc/qtcreator/src/external-resources/external-resources-qds.qdoc @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \externalpage https://doc.qt.io/qtdesignstudio/index.html + \title Qt Design Studio Manual +*/ +/*! + \externalpage https://doc.qt.io/qtdesignstudio/studio-optimized-3d-scenes.html + \title Creating Optimized 3D Scenes +*/ +/*! + \externalpage https://doc.qt.io/qtdesignstudio/qtquick-optimizing-designs.html + \title Optimizing Designs +*/ +/*! + \externalpage https://doc.qt.io/qtdesignstudio/studio-optimized-3d-scenes.html + \title Creating Optimized 3D Scenes +*/ diff --git a/doc/qtcreator/src/external-resources/external-resources.qdoc b/doc/qtcreator/src/external-resources/external-resources.qdoc index 09c650e3a94..a6ddbe1414f 100644 --- a/doc/qtcreator/src/external-resources/external-resources.qdoc +++ b/doc/qtcreator/src/external-resources/external-resources.qdoc @@ -101,3 +101,11 @@ \externalpage http://developer.android.com/guide/components/fundamentals.html \title Android Application Fundamentals */ +/*! + \externalpage https://doc.qt.io/qt/qtqml-cppintegration-overview.html + \title Overview - QML and C++ Integration +*/ +/*! + \externalpage https://doc.qt.io/qt/qtqml-syntax-imports.html#qml-import-path + \title QML Import Path +*/ diff --git a/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc b/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc index 9d869b62540..56d78ffcd3b 100644 --- a/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc +++ b/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc @@ -580,10 +580,11 @@ \endtable \endif + \if defined(qtdesignstudio) \section2 Design Mode Keyboard Shortcuts You can use the following keyboard shortcuts when editing QML files in the - Design mode. + \uicontrol Design mode. \table \header @@ -603,6 +604,7 @@ \li Toggle right sidebar \li Ctrl+Alt+Shift+0 \endtable + \endif \section2 Debugging Keyboard Shortcuts diff --git a/doc/qtcreator/src/howto/creator-only/qtcreator-faq.qdoc b/doc/qtcreator/src/howto/creator-only/qtcreator-faq.qdoc index 9338321da0d..c039d22c379 100644 --- a/doc/qtcreator/src/howto/creator-only/qtcreator-faq.qdoc +++ b/doc/qtcreator/src/howto/creator-only/qtcreator-faq.qdoc @@ -104,7 +104,7 @@ \b {What should I do when \QC complains about missing OpenGL support?} - Some parts of \QC, such as the Design mode and QML Profiler, use Qt Quick 2, which + Some parts of \QC, such as QML Profiler, use Qt Quick 2, which relies on OpenGL API for drawing. Unfortunately, the use of OpenGL can cause problems, especially in remote setups and with outdated drivers. In these cases, \QC displays OpenGL-related error messages on the console or records diff --git a/doc/qtcreator/src/howto/creator-telemetry.qdoc b/doc/qtcreator/src/howto/creator-telemetry.qdoc index 746c4b4efb6..8ae161c74e3 100644 --- a/doc/qtcreator/src/howto/creator-telemetry.qdoc +++ b/doc/qtcreator/src/howto/creator-telemetry.qdoc @@ -84,7 +84,7 @@ \page collecting-usage-statistics.html \previouspage creator-telemetry.html \if defined(qtdesignstudio) - \nextpage collecting-user-feedback.html + \nextpage studio-user-feedback.html \else \nextpage creator-help-overview.html \endif @@ -116,67 +116,3 @@ that you do not want to transmit to the backend storage. \endlist */ - -/*! - \page collecting-user-feedback.html - \previouspage collecting-usage-statistics.html - \nextpage creator-crashpad.html - - \title Collecting User Feedback - - A pop-up survey asking for your feedback will appear for some of the features - after you have been using them for some time. You will be asked to to rate - the usefulness of the feature on a scale of one to five stars. You must rate - the feature with at least one star if you wish to submit your rating. You - are also encouraged to give additional written feedback. After you select - \uicontrol Skip or \uicontrol Submit, the pop-up survey will not appear for - the same feature again. - - \image studio-feedback-popup.png "User feedback pop-up survey for Flow Editor" - - For the pop-up survey to appear, you must enable collecting statistics, and - also allow collecting \uicontrol {4 - Detailed usage statistics} in - \uicontrol Tools > \uicontrol Options > \uicontrol Telemetry > - \uicontrol {Usage Statistics} > \uicontrol {Telemetry mode}. - You can review the submitted user feedback in - \uicontrol Tools > \uicontrol Options > \uicontrol Telemetry > - \uicontrol {Usage Statistics} > \uicontrol {Collected Data} by selecting - \uicontrol {Qt Quick Designer Usage of views and actions} in - \uicontrol {Data sources}. -*/ - -/*! - \page creator-crashpad.html - \previouspage collecting-user-feedback.html - \nextpage studio-packaging.html - - \title Reporting Crashes - - You can enable \QDS to report crashes automatically. \QDS uses Google - Crashpad to collect crashes and report them to the Sentry backend storage - for processing. The purpose of Crashpad is to capture application state in - sufficient detail to allow developers to diagnose and, where possible, fix - the issue causing the crash. Crashpad may capture arbitrary contents from - the memory of a crashed process, including user sensitive information, URLs, - and other content provided by the users. The collected reports are used for - the sole purpose of fixing bugs. For more information on Crashpad, see the - \l {https://chromium.googlesource.com/crashpad/crashpad/+/master/doc/overview_design.md} - {documentation} by Google. For more information on processing and storing - of the collected data, see \l {https://sentry.io/security/} - {Security & Compliance} by Sentry. - - To enable sending crash reports, select \uicontrol Tools > \uicontrol - Options > \uicontrol Environment > \uicontrol System - (\uicontrol {Qt Design Studio} > \uicontrol Preferences > \uicontrol - Environment > \uicontrol System on \macos), and then select - \uicontrol {Enable crash reporting}. - - Since crash reports take up disk space, you may wish to remove them when - they are no longer needed. Select \uicontrol {Clear local crash reports} to - remove the crash report data. - - \image studio-crashpad-checkbox.png "Checkbox for enabling crash reporting" - - \note Crashpad is currently only supported on Windows and \macos. - -*/ diff --git a/doc/qtcreator/src/overview/creator-only/creator-commercial-overview.qdoc b/doc/qtcreator/src/overview/creator-only/creator-commercial-overview.qdoc index a227fe0d194..acb4548fb3c 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-commercial-overview.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-commercial-overview.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -40,7 +40,6 @@ \l{http://qt.io/licensing/}{Qt license}: \list - \li \l{Browsing ISO 7000 Icons} in the Design mode \li \l{http://doc.qt.io/QtForDeviceCreation/index.html}{Developing for embedded devices} \li \l{http://doc.qt.io/qtcreator/creator-overview-qtasam.html} diff --git a/doc/qtcreator/src/overview/creator-only/creator-design-overview.qdoc b/doc/qtcreator/src/overview/creator-only/creator-design-overview.qdoc index 1832facb558..5b530662a6c 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-design-overview.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-design-overview.qdoc @@ -38,16 +38,19 @@ \image front-ui.png - \QC provides integrated visual editors for designing Qt Quick and - widget-based applications in the Design mode. The integration - includes project management and code completion. + \QC provides an integrated visual editor designing widget-based applications + in the \uicontrol Design mode. The integration includes project management + and code completion. + + You can develop Qt Quick applications in the \uicontrol Edit mode or use + a separate visual editor, \QDS. \list \li \l{Developing Qt Quick Applications} You can use wizards to create Qt Quick projects containing - boiler-plate code that you can edit in the Design mode. + boiler-plate code that you can edit in the \uicontrol Edit mode. \li \l{Developing Widget Based Applications} diff --git a/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc b/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc index 578a2892192..bac658aef58 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc @@ -143,15 +143,4 @@ {GCC Bugzilla - Bug 44731}. \endlist - - \section1 Design Mode Issues - - \list - - \li The Design mode uses a QML emulation layer (QML Puppet) to render and preview - images and to collect data. Executing C++ code might cause the QML - emulation layer to crash. If it crashes, an error message is displayed and - you can continue editing the QML file in the code editor. - - \endlist */ diff --git a/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc b/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc index 98415f37608..6b4576e0772 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc @@ -64,10 +64,8 @@ \l{Managing Projects}. \li \b {\l{Designing User Interfaces}} - \QC provides integrated visual editors for creating Qt Quick and - widget-based applications in the Design mode. To create intuitive, modern-looking, fluid user interfaces, you - can use \l{Qt Quick}. + can use \l{Qt Quick} and \QDS. If you need a traditional user interface that is clearly structured and enforces a platform look and feel, you can use the integrated \QD. For more information, see diff --git a/doc/qtcreator/src/overview/creator-only/creator-tutorials.qdoc b/doc/qtcreator/src/overview/creator-only/creator-tutorials.qdoc index 912863c18e1..698289d48f5 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-tutorials.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-tutorials.qdoc @@ -46,7 +46,7 @@ \li \l{Creating a Qt Quick Application} - Learn how to use the Design mode to create a Qt Quick application. + Learn how to create a Qt Quick application. \li \l{Creating a Qt Widget Based Application} diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index e38b0bdea64..c1ce9e2f2f5 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -103,105 +103,9 @@ \li \l{Developing Qt Quick Applications} \list \li \l {Creating Qt Quick Projects} - \li \l {Design Views} - \list - \li \l{Form Editor} - \li \l{3D Editor} - \li \l{Library} - \li \l{Navigator} - \li \l{Properties} - \li \l{Connection View} - \li \l{States} - \li \l{Transition Editor} - \li \l{Timeline} - \li \l{Curve Editor} - \li \l{Text Editor} - \endlist - \li \l {Wireframing} - \list - \li \l {Components} - \list - \li \l {Preset Components} - \list - \li \l{Shapes} - \li \l{Text} - \li \l{Images} - \li \l{UI Controls} - \li \l{User Interaction Methods} - \li \l{Lists and Other Data Models} - \li \l{Animations} - \li \l{3D Views} - \li \l{Node} - \li \l{Group} - \li \l{Instanced Rendering} - \li \l{Skeletal Animation} - \li \l{3D Models} - \li \l{Materials and Shaders} - \li \l{Textures} - \li \l{3D Materials} - \li \l{3D Effects} - \li \l{Custom Shaders} - \li \l{Custom Effects and Materials} - \li \l{Lights} - \li \l{Cameras} - \li \l{Scene Environment} - \li \l{Morph Target} - \li \l{Repeater3D} - \li \l{Loader3D} - \endlist - \li \l {Creating Component Instances} - \li \l {Creating Custom Components} - \list - \li \l{Creating Buttons} - \li \l{Creating Scalable Buttons and Borders} - \endlist - \endlist - \li \l{Specifying Component Properties} - \li \l{Scalable Layouts} - \li \l{Using Custom Fonts} - \li \l{Annotating Designs} - \li \l{UI Files} - \endlist - \li \l{Prototyping} - \list - \li \l{Creating UI Logic} - \li \l{Simulating Complex Experiences} - \list - \li \l{Loading Placeholder Data} - \li \l{Using QML Modules with Plugins} - \endlist - \li \l {Dynamic Behaviors} - \list - \li \l{Adding Connections} - \list - \li \l{Connecting Components to Signals} - \li \l{Adding Bindings Between Properties} - \li \l{Specifying Dynamic Properties} - \li \l{Managing C++ Backend Objects} - \endlist - \li \l {Adding States} - \endlist - \li \l {Exporting 3D Assets} - \list - \li \l{Exporting from Blender}{Blender} - \li \l{Exporting from Maya}{Maya} - \endlist - \li \l{Importing 3D Assets} - \li \l{Exporting Components} - \endlist - \li \l{Motion Design} - \list - \li \l{Introduction to Animation Techniques} - \li \l{Creating Timeline Animations} - \li \l{Editing Easing Curves} - \li \l{Production Quality} - \li \l{Optimizing Designs} - \list - \li \l{Creating Optimized 3D Scenes} - \endlist - \endlist - \li \l {Browsing ISO 7000 Icons} \li \l {Converting UI Projects to Applications} + \li \l {UI Files} + \li \l {Using QML Modules with Plugins} \endlist \li \l{Developing Widget Based Applications} \list diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-app-development.qdoc b/doc/qtcreator/src/qtquick/creator-only/qtquick-app-development.qdoc index ee038bcd218..3f05a77c06f 100644 --- a/doc/qtcreator/src/qtquick/creator-only/qtquick-app-development.qdoc +++ b/doc/qtcreator/src/qtquick/creator-only/qtquick-app-development.qdoc @@ -36,64 +36,31 @@ \title Developing Qt Quick Applications + You can develop Qt Quick applications in the \uicontrol Edit mode or use + a separate visual editor, \QDS. + + If you have installed \QDS, and open a .ui.qml or a .qml file in \QC, it + asks you whether you would like to open the file in \QDS instead. Select + \uicontrol {Open in \QDS} to open the file in \QDS. To continue editing + the file in \QC, close the info bar. However, we do not recommend editing + \l{UI Files}{UI files} in the \uicontrol Edit mode, because it is easy to + add code that is not supported by \QDS. To hide the question, select + \uicontrol {Do Not Show Again}. + + For more information about using \QDS, see \l{Qt Design Studio Manual}. + + For more information about \l{Qt QML}, \l{Qt Quick}, and \l{All QML Types} + {QML types}, see the Qt reference documentation available online and + in the \uicontrol Help mode. + + The following topics describe Qt Quick application development using \QC: + \list \li \l {Creating Qt Quick Projects} You can use wizards to create Qt Quick projects. - \li \l {Design Views} - - You can use several different editors and views in the - Design mode to develop Qt Quick applications. - - \li \l {Wireframing} - - Plan your UI properly. Know what elements, such as screens, - components, and states, you need. Create a descriptive wireframe - and acquire a detailed UI specification before you start to make - the process of creating the UI more efficient. - - \li \l {Prototyping} - - After your UI wireframe has been approved, you can turn it into - an interactive prototype to ensure that you and the developers - share a common vision about the UI appearance and functionality. - - \li \l{Motion Design} - - After the wireframing and prototyping phases, you can use the - supported motion design techniques to fine-tune your UI for - production. You can use different animation techniques for - different purposes. \QC supports common motion design techniques, - such as timeline and keyframe based animation and easing curves, - as well as screen-to-screen or state-to-state application flows - and data-driven UI logic animation. - - \endlist - - For more information, watch a video that shows how to perform the tasks - above: - - \youtube pEETxSxYazg - - \section1 Related Topics - - \list - - \li \l {Browsing ISO 7000 Icons} - - You can add ISO 7000 icons from a library delivered with \QC to - UIs and change their color. - - \li \l {Using QML Modules with Plugins} - - QML modules may use plugins to expose components defined in C++ to - QML applications. \QC cannot load the plugins to determine the - details of the contained components, and therefore, the modules must - provide extra type information for code completion and the semantic - checks to work correctly. - \li \l {Converting UI Projects to Applications} Qt Quick UI projects (.qmlproject) are useful for creating user @@ -101,11 +68,15 @@ convert them to Qt Quick Application projects that contain .pro, .cpp, and .qrc files. - \li \l {Exporting Components} + \li \l {UI Files} - \l{UI Files}{UI files} (.ui.qml) can be exported to - JSON metadata format and PNG assets. + If you switch between \QC and \QDS or cooperate with designers on + a project, you might encounter .ui.qml files. They are intended to + be edited in \QDS only, so you need to be careful not to break the + code. + \li \l{Using QML Modules with Plugins} + + You can load C++ plugins for QML to simulate data. \endlist - */ diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-connection-editor-backend.qdoc b/doc/qtcreator/src/qtquick/creator-only/qtquick-connection-editor-backend.qdoc deleted file mode 100644 index afd9d07e584..00000000000 --- a/doc/qtcreator/src/qtquick/creator-only/qtquick-connection-editor-backend.qdoc +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Creator documentation. -** -** 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 Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** -****************************************************************************/ - -/*! - \previouspage quick-dynamic-properties.html - \page quick-connections-backend.html - \nextpage quick-states.html - - \title Managing C++ Backend Objects - - Many applications provide QObject objects implemented in C++ that work as a - bridge between QML and C++. Such objects are typically registered with - \c qmlRegisterType or \c qmlRegisterSingletonType and then used by QML to - communicate with the C++ backend. Another example of such objects are the - state machines created by the \l {Using the Qt SCXML Compiler (qscxmlc)} - {Qt SCXML Compiler}. - - Backend objects in a QML file are accessible if the QML file contains the - required imports. In addition, for a non-singleton QObject, a dynamic - property that contains the QObject must be specified. - - A \e local QObject is instantiated in the current \e .qml file, as follows: - - \badcode - property MyType myType: MyType {}. - \endcode - - Otherwise the property is just defined, as follows: - - \badcode - property MyType myType - \endcode - - To manage backend objects: - - \list 1 - - \li Select \uicontrol {Connection View} > \uicontrol Backends to view - accessible backend objects. - \image qmldesigner-backends.png "Connection View, Backends tab" - \li Select the \inlineimage plus.png - (\uicontrol Add) button to add a backend object in the - \uicontrol {Add New C++ Backend} dialog. - \image qmldesigner-backends-add.png "Add New C++ Backend dialog" - \li In the \uicontrol Type field, select the backend QObject to add. - \li Select the \uicontrol {Define object locally} check box if the - QObject is not registered as a singleton. - \li Select \uicontrol OK to add the required import and to create the - property for a non-singleton object. - \endlist -*/ diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-iso-icon-browser.qdoc b/doc/qtcreator/src/qtquick/creator-only/qtquick-iso-icon-browser.qdoc deleted file mode 100644 index 48dbe68617e..00000000000 --- a/doc/qtcreator/src/qtquick/creator-only/qtquick-iso-icon-browser.qdoc +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Creator documentation. -** -** 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 Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** -****************************************************************************/ - -/*! - \page qtquick-iso-icon-browser.html - \previouspage studio-3d-scene-environment.html - \nextpage quick-converting-ui-projects.html - - \title Browsing ISO 7000 Icons - - \commercial - - You can add icons from an ISO 7000 icon library that is installed with \QC - to Qt Quick applications (commercial only). You can use the - \uicontrol {ISO Icon Browser} to add a \l {Picture} component and select the - icon to use for the component. You can change the default color of the icon. - - \image qtcreator-iso-icon-browser.png - - \section1 Using ISO Icons in Applications - - \list 1 - - \li Create a new Qt Quick Application or open an application in \QC. - - \li Open the \l{UI Files}{UI file} (.ui.qml) in \l {Form Editor}. - - \li Select \l Library > \uicontrol Components > \inlineimage plus.png - > \uicontrol {QtQuick.Extras} to import the \l {Qt Quick Extras} - module. - - \li Drag and drop a \uicontrol Picture component from \uicontrol Library - to \l {Form Editor}. - - \li Right-click the picture component and select \uicontrol {Choose Icon} - to open the \uicontrol {ISO Icon Browser}. - - \li To find icons, select a criterion for filtering icons and enter a - search string. - - \li Select an icon in the list, and then select \uicontrol OK to add - the icon. - - \li To view the icon you added, press \key {Ctrl+R} (or \key {Cmd+R}) - to run the application. - - \li To adjust the icon color, select the icon on the canvas, and then - select \uicontrol {Edit Color} in the context menu. - - \endlist - - \QC generates a Qt resource file called \c iso-icons.qrc that adds the - icons as a part of your project for delivery with your application. - - */ diff --git a/doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc b/doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc index 1f3f5c0adc4..9a6a39645c7 100644 --- a/doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc @@ -29,8 +29,8 @@ \previouspage studio-porting-projects.html \nextpage creator-editor-external.html \else - \previouspage qtquick-iso-icon-browser.html - \nextpage creator-using-qt-designer.html + \previouspage quick-projects.html + \nextpage creator-quick-ui-forms.html \endif \title Converting UI Projects to Applications @@ -47,8 +47,7 @@ \endlist For more information about integrating QML and C++, see - \l{https://doc.qt.io/qt/qtqml-cppintegration-overview.html} - {Overview - QML and C++ Integration}. + \l{Overview - QML and C++ Integration}. You can use a Qt Creator wizard template to create a Qt Quick application that is built using the qmake build system and then copy the source files @@ -61,10 +60,8 @@ compiling them into the binary. The wizard automatically adds the \c QML_IMPORT_PATH option to the project - file for specifying the required - \l{https://doc.qt.io/qt/qtqml-syntax-imports.html#qml-import-path} - {QML import path}. The path is only needed if more than one subdirectory - contains QML files. + file for specifying the required \l{QML Import Path}{QML import path}. The + path is only needed if more than one subdirectory contains QML files. Then you can use the \l QQuickView class in the main C++ source file to show the main QML file when the application starts. @@ -90,8 +87,8 @@ \list 1 \li Select \uicontrol File > \uicontrol {New File or Project} > - \uicontrol {Application (Qt Quick)} > - \uicontrol {Qt Quick Application - Empty} > \uicontrol Choose. + \uicontrol {Application (Qt)} > \uicontrol {Qt Quick Application} > + \uicontrol Choose. \li In the \uicontrol {Build system} field, select \l qmake as the build system to use for building and running the project, and then select \uicontrol Next (or \uicontrol Continue on \macos). @@ -151,9 +148,13 @@ \section1 Adding Custom Fonts - To \l{Using Custom Fonts}{use custom fonts} from the Qt Quick UI project, - call the QFontDatabase::addApplicationFont() function from the \e {main.cpp} - file. + \if defined(qtdesignstudio) + To \l{Using Custom Fonts}{use custom fonts} + \else + To use custom fonts + \endif + from the Qt Quick UI project, call the QFontDatabase::addApplicationFont() + function from the \e {main.cpp} file. \section1 Adding Qt Quick Designer Components to Qt Installations diff --git a/doc/qtcreator/src/qtquick/qtquick-live-preview-desktop.qdoc b/doc/qtcreator/src/qtquick/qtquick-live-preview-desktop.qdoc index a87e833683b..5031c569387 100644 --- a/doc/qtcreator/src/qtquick/qtquick-live-preview-desktop.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-live-preview-desktop.qdoc @@ -30,6 +30,12 @@ \title Previewing on Desktop + \if defined(qtcreator) + To preview the currently active QML file on the desktop, select + \uicontrol Build > \uicontrol {QML Preview}. + + \image qtcreator-live-preview.png + \else To preview the currently active QML file on the desktop: \list @@ -39,24 +45,21 @@ \li Press \key {Alt+P}. \endlist - \if defined(qtcreator) - \image qtcreator-live-preview.png - \else \image studio-live-preview.png \endif To preview any QML file that belongs to the project, right-click the project - name in the \uicontrol Projects view, and select \uicontrol {Preview file}. + name in the \l Projects view, and select \uicontrol {Preview File}. + \if defined(qtdesignstudio) To preview the whole UI, select \uicontrol {Show Live Preview} - when viewing the main QML UI file of the project. + when viewing the main QML file of the project. To view the UI in different sizes, select the zooming level on the toolbar. The frames-per-second (FPS) refresh rate of animations is displayed in the \uicontrol FPS field. - \if defined(qtdesignstudio) \section1 Selecting the Preview Tool By default, the QML runtime is used for previewing. To use some diff --git a/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc b/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc index f6577915c94..d851236c7d2 100644 --- a/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc @@ -25,7 +25,11 @@ /*! \page creator-live-preview.html + \if defined(qtdesignstudio) \previouspage quick-states.html + \else + \previouspage creator-building-running.html + \endif \nextpage creator-live-preview-desktop.html \title Validating with Target Hardware @@ -53,8 +57,7 @@ \list \li \l{Previewing on Desktop} - You can preview individual QML files or the whole UI in the - Design mode. + You can preview individual QML files or the whole UI. \li \l{Previewing on Devices} \if defined(qtcreator) diff --git a/doc/qtcreator/src/qtquick/qtquick-modules-with-plugins.qdoc b/doc/qtcreator/src/qtquick/qtquick-modules-with-plugins.qdoc index 31b69054fad..85f7c0135be 100644 --- a/doc/qtcreator/src/qtquick/qtquick-modules-with-plugins.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-modules-with-plugins.qdoc @@ -33,10 +33,11 @@ \page creator-qml-modules-with-plugins.html \if defined(qtdesignstudio) \previouspage studio-simulink.html - \else - \previouspage qtquick-placeholder-data.html - \endif \nextpage qtquick-adding-dynamics.html + \else + \previouspage creator-quick-ui-forms.html + \nextpage creator-using-qt-designer.html + \endif \title Using QML Modules with Plugins @@ -45,7 +46,12 @@ the contained components, and therefore, the modules must provide extra type information for code completion and the semantic checks to work correctly. - To create a QML module and make it appear in the \l Library view: + To create a QML module + \if defined(qtdesignstudio) + and make it appear in the \l Library view: + \else + : + \endif \list 1 @@ -69,29 +75,27 @@ \li Create a directory named \c designer in your module directory. \li Create a \c .metainfo file for your module and place it in the - \c designer directory. Meta information is needed to display the + \c designer directory. + \if defined(qtdesignstudio) + Meta information is needed to display the components in the \uicontrol Components tab in \uicontrol Library. + \endif Use a metainfo file delivered with Qt, such as \c qtquickcontrols2.metainfo, as an example. \if defined(qtcreator) \li Import the module into the project, as instructed in \l {Importing QML Modules}. - - \li Make sure that the QML emulation layer used in the Design mode is built with - the same Qt version as your QML modules. For more information, see - \l {Running QML Modules in Design Mode}. You can also try - skipping this step and take it later, if necessary. + \endlist \else \li Build your module using the same Qt version and compiler as \QDS. For more information, see \l {Running QML Modules in Design Mode}. - \endif - - \endlist + \endlist Your module should now appear in the \uicontrol Components tab in \uicontrol Library. Your components should appear in a subsection of the \uicontrol Components tab if a valid \c .metainfo file is in place. + \endif \if defined(qtcreator) \section1 Registering QML Types @@ -105,9 +109,6 @@ complain about unknown types. However, this works only when the source code is available, and therefore, you must explicitly generate type information for QML modules with plugins before distributing them. - - Classes registered with \c qmlRegisterType() can be used as backend objects - in the Design mode. For more information, see \l {Adding Connections}. \endif \section1 Generating qmltypes Files @@ -168,26 +169,16 @@ \endcode The import path affects all the targets built by the CMake project. - \endif + \else \section1 Running QML Modules in Design Mode - A QML emulation layer (also called QML Puppet) is used in the Design mode to - render and preview images and to collect data. To be able to render custom components - correctly from QML modules, the emulation layer must be built with the same - Qt version and compiler as the QML modules. + A QML emulation layer (also called QML Puppet) is used in the + \uicontrol Design mode to render and preview images and to collect + data. To be able to render custom components correctly from QML modules, + the emulation layer must be built with the same Qt version and compiler + as the QML modules. - \if defined(qtcreator) - By default, a fallback emulation layer is provided by \QC and built with the same - Qt version as \QC. Therefore, your QML modules will mostly not work out of - the box. - - To use an emulation layer that is built with the Qt - configured in the build and run kit for the project, select \uicontrol Tools > - \uicontrol Options > \uicontrol {Qt Quick} > \uicontrol {Qt Quick Designer} > - \uicontrol {Use QML emulation layer which is built by the selected Qt} radio button. - \QC builds the emulation layer when you select the Design mode. - \else On Windows, select \uicontrol Help > \uicontrol {About Qt Design Studio} to check the Qt version and compiler that you need to use to build your plugin. For example: \c {Based on Qt 5.15.2 (MSVC 2019, 64 bit)}. @@ -195,21 +186,20 @@ On macOS, select \uicontrol {Qt Design Studio} > \uicontrol {About Qt Design Studio} to see something like: \c {Based on Qt 5.15.2 (Clang 10.0 (Apple), 64 bit)}. - \endif - A plugin should behave differently depending on whether it is run by the emulation layer or an application. For example, animations should not be run - in the Design mode. You can use the value of the \c QML_PUPPET_MODE + in the \uicontrol Design mode. You can use the value of the \c QML_PUPPET_MODE environment variable to check whether the plugin is currently being run - by an application or edited in the Design mode. + by an application or edited in the \uicontrol Design mode. - If you want to use a different module in the Design mode than in your actual - application for example to mockup C++ items, then you can use \c{QML_DESIGNER_IMPORT_PATH} + If you want to use a different module in the \uicontrol Design mode + than in your actual application for example to mockup C++ items, + you can use \c{QML_DESIGNER_IMPORT_PATH} in the \c{.pro} file (for qmake projects), or declare and set the property \c qmlDesignerImportPaths in your product (for Qbs projects). Modules in the import paths defined in \c{QML_DESIGNER_IMPORT_PATH} will be - used only in the Design mode. + used only in the \uicontrol Design mode. For an example, see \l {Qt Quick Controls - Contact List}. - + \endif */ diff --git a/doc/qtcreator/src/qtquick/qtquick-toolbars.qdoc b/doc/qtcreator/src/qtquick/qtquick-toolbars.qdoc index de00b1e0edd..33c88a9ae36 100644 --- a/doc/qtcreator/src/qtquick/qtquick-toolbars.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-toolbars.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -56,7 +56,13 @@ \section1 Previewing Images The Qt Quick Toolbar for images allows you to edit the properties of - \l {Border Image} and \l {Images}{Image} items. + \l {Border Image} and + \if defined(qtdesignstudio) + \l {Images}{Image} items. + \else + \l Image items. + \endif + You can scale and tile the images, replace them with other images, preview them, and change the image margins. @@ -97,8 +103,12 @@ \section1 Editing Rectangles The Qt Quick Toolbar for rectangles allows you to edit the properties of - \l {basic-rectangle}{Rectangle} items. You can change the fill and border - colors and add gradients. + \if defined(qtdesignstudio) + \l {basic-rectangle}{Rectangle} + \else + Rectangle + \endif + items. You can change the fill and border colors and add gradients. \image qml-toolbar-rectangle.png "Qt Quick Toolbar for rectangles" diff --git a/doc/qtcreator/src/qtquick/qtquick-ui-forms.qdoc b/doc/qtcreator/src/qtquick/qtquick-ui-forms.qdoc index 71fddd3d062..fb76d5250cb 100644 --- a/doc/qtcreator/src/qtquick/qtquick-ui-forms.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-ui-forms.qdoc @@ -35,18 +35,24 @@ \previouspage studio-advanced.html \nextpage creator-telemetry.html \else - \previouspage qtquick-annotations.html - \nextpage qtquick-prototyping.html + \previouspage quick-converting-ui-projects.html + \nextpage creator-qml-modules-with-plugins.html \endif \title UI Files - You can use \QC wizards to create UI files that have the filename + \if defined(qtdesignstudio) + You can use \QDS wizards to create UI files that have the filename extension \e .ui.qml. The UI files can be edited in \l {Form Editor}. If you use \l {Text Editor} to add code that is not supported - by \uicontrol {Form Editor}, \QC displays error messages. + by \uicontrol {Form Editor}, \QDS displays error messages. + \else + If you switch between \QC and \QDS or cooperate with designers on + a project, you might encounter UI files (.ui.qml). They are intended to + be edited in \QDS only. + \endif - The following features are not supported: + The following features are not supported in .ui.qml files: \list \li JavaScript blocks @@ -162,6 +168,7 @@ For more information about using the methods, see \l{https://doc.qt.io/qt/qml-qtqml-qt.html}{Qt QML Methods}. + \if defined(qtdesignstudio) \section1 Using UI Files You can edit the UI files in the \l {Form Editor} and @@ -207,5 +214,5 @@ implementation of a component in the .qml file, right-click the component and select \uicontrol {Go to Implementation} in the context menu. - + \endif */ diff --git a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc index 35792c6b690..630c0a1996c 100644 --- a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc @@ -33,6 +33,7 @@ If you cannot see a file in the \l Projects view, switch to the \uicontrol {File System} view, which shows all the files in the file system. + \if defined(qtdesignstudio) The following image displays the \uicontrol {File System} view in the \uicontrol Design mode: @@ -89,6 +90,7 @@ \endlist \section1 File System View in Sidebar + \endif In the \uicontrol Edit and \uicontrol Debug mode, the \uicontrol {File System} view is displayed in the \l{Working with Sidebars} diff --git a/doc/qtcreator/src/user-interface/creator-open-documents-view.qdoc b/doc/qtcreator/src/user-interface/creator-open-documents-view.qdoc index 64358b87aac..c64809d8f2b 100644 --- a/doc/qtcreator/src/user-interface/creator-open-documents-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-open-documents-view.qdoc @@ -35,8 +35,13 @@ \image qtcreator-open-documents-view.png "Open Documents view" You can use the context menu to apply some of the functions also available - in the \uicontrol File menu and in the \l {File System Context Menu} - {File System} view to the file that is selected in the view. + in the \uicontrol File menu + \if defined(qtcreator) + . + \else + and in the \l {File System Context Menu} {File System} view to the file + that is selected in the view. + \endif In addition, you can: diff --git a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc index a9f50806f49..cc9f5cbcfe4 100644 --- a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc @@ -40,6 +40,7 @@ the build system structure of the project and lists all files that are part of the project. + \if defined(qtdesignstudio) The following image displays the \uicontrol Projects view in the \uicontrol Design mode: @@ -65,14 +66,6 @@ configuration files. \endlist - \if defined(qtcreator) - Files that are not sources or data can be still included into a project's - distribution tarball by adding their paths to the \c DISTFILES variable in - the .pro file. This way they also become known to \QC, so that they are - visible in the \uicontrol Projects view and are known to the locator and - search. - \endif - \section1 Projects View Context Menu The \uicontrol Projects view contains context menus for managing projects, @@ -114,6 +107,7 @@ the \l {File System} view. \section1 Projects View in Sidebar + \endif In the \uicontrol Edit and \uicontrol Debug mode, the \uicontrol Projects view is displayed in the \l{Working with Sidebars}{sidebar}. It has a diff --git a/doc/qtcreator/src/user-interface/creator-ui.qdoc b/doc/qtcreator/src/user-interface/creator-ui.qdoc index 5bf6d486893..7711dbd01f6 100644 --- a/doc/qtcreator/src/user-interface/creator-ui.qdoc +++ b/doc/qtcreator/src/user-interface/creator-ui.qdoc @@ -292,11 +292,6 @@ \uicontrol View > \uicontrol {Mode Selector Style} > \uicontrol Hidden. To only show icons on the mode selector, select the \uicontrol {Icons Only} style. - - The following image displays an example application in \uicontrol Edit mode (1) - and \uicontrol Design mode (2). - - \image qtcreator-qt-quick-editors.png "Edit mode and Design mode" \endif You can use \QC in the following modes: diff --git a/doc/qtcreator/src/user-interface/creator-views.qdoc b/doc/qtcreator/src/user-interface/creator-views.qdoc index dd45f9411ef..65e44a03a91 100644 --- a/doc/qtcreator/src/user-interface/creator-views.qdoc +++ b/doc/qtcreator/src/user-interface/creator-views.qdoc @@ -70,10 +70,10 @@ files are included in the current file and which files include the current file. \endlist - \endif - + \else For more information about views that are only available when editing QML - files in the Design mode, see \l{Design Views}. + files in the \uicontrol Design mode, see \l{Design Views}. + \endif The additional options in a particular view are described in the following sections. diff --git a/doc/qtcreator/src/widgets/creator-faq-qtdesigner.qdocinc b/doc/qtcreator/src/widgets/creator-faq-qtdesigner.qdocinc index f341ce664c3..64a607ab05c 100644 --- a/doc/qtcreator/src/widgets/creator-faq-qtdesigner.qdocinc +++ b/doc/qtcreator/src/widgets/creator-faq-qtdesigner.qdocinc @@ -28,12 +28,12 @@ \section1 Qt Designer Integration Questions - \b {Why are custom widgets not loaded in Design mode even though it - works in standalone Qt Designer?} + \b {Why are custom widgets not loaded in the \uicontrol Design mode even though + it works in standalone \QD?} - Qt Designer fetches plugins from standard locations and loads the plugins + \QD fetches plugins from standard locations and loads the plugins that match its build key. The locations are different for standalone and - integrated Qt Designer. + integrated \QD. For more information, see \l{Adding Qt Designer Plugins}. diff --git a/doc/qtcreator/src/widgets/qtdesigner-overview.qdoc b/doc/qtcreator/src/widgets/qtdesigner-overview.qdoc index e2342dbe416..42a547d44f9 100644 --- a/doc/qtcreator/src/widgets/qtdesigner-overview.qdoc +++ b/doc/qtcreator/src/widgets/qtdesigner-overview.qdoc @@ -30,7 +30,7 @@ // ********************************************************************** /*! - \previouspage creator-exporting-qml.html + \previouspage creator-qml-modules-with-plugins.html \page creator-using-qt-designer.html \nextpage adding-plugins.html diff --git a/doc/qtcreator/src/qtquick/qtquick-animation-types.qdoc b/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-animation-types.qdoc rename to doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-buttons.qdoc b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-buttons.qdoc rename to doc/qtdesignstudio/src/components/qtquick-buttons.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-component-context-menu.qdocinc b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-component-context-menu.qdocinc rename to doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-component-instances.qdoc b/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-component-instances.qdoc rename to doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-components-custom.qdoc b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-components-custom.qdoc rename to doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-components.qdoc b/doc/qtdesignstudio/src/components/qtquick-components.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-components.qdoc rename to doc/qtdesignstudio/src/components/qtquick-components.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-controls.qdoc b/doc/qtdesignstudio/src/components/qtquick-controls.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-controls.qdoc rename to doc/qtdesignstudio/src/components/qtquick-controls.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc b/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc rename to doc/qtdesignstudio/src/components/qtquick-data-models.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-images.qdoc b/doc/qtdesignstudio/src/components/qtquick-images.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-images.qdoc rename to doc/qtdesignstudio/src/components/qtquick-images.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-pathview-editor.qdocinc b/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-pathview-editor.qdocinc rename to doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc diff --git a/doc/qtcreator/src/qtquick/qtquick-positioning.qdoc b/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-positioning.qdoc rename to doc/qtdesignstudio/src/components/qtquick-positioning.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-preset-components.qdoc b/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-preset-components.qdoc rename to doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-shapes.qdoc b/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-shapes.qdoc rename to doc/qtdesignstudio/src/components/qtquick-shapes.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-text.qdoc b/doc/qtdesignstudio/src/components/qtquick-text.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-text.qdoc rename to doc/qtdesignstudio/src/components/qtquick-text.qdoc diff --git a/doc/qtcreator/src/qtquick/library/qtquick-user-interaction-methods.qdoc b/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/library/qtquick-user-interaction-methods.qdoc rename to doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc diff --git a/doc/qtcreator/src/qtquick/qtdesignstudio-simulation-overview.qdoc b/doc/qtdesignstudio/src/overviews/qtdesignstudio-simulation-overview.qdoc similarity index 92% rename from doc/qtcreator/src/qtquick/qtdesignstudio-simulation-overview.qdoc rename to doc/qtdesignstudio/src/overviews/qtdesignstudio-simulation-overview.qdoc index e5899fe3de9..b62198deb82 100644 --- a/doc/qtcreator/src/qtquick/qtdesignstudio-simulation-overview.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtdesignstudio-simulation-overview.qdoc @@ -30,14 +30,11 @@ \title Simulating Complex Experiences - \QDS enables you to connect UIs to different forms of data from various sources, such as QML-based data models, JavaScript files, and backend - services. - \if definded(qtdesignstudio) - You can also connect your UI to Simulink to load live data from a + services. You can also connect your UI to Simulink to load live data from a Simulink simulation. - \endif + \list \li \l{Loading Placeholder Data} @@ -46,7 +43,6 @@ you can test grid, list, or path views, even though you don't have access to real data. - \if defined(qtdesignstudio) \li \l{Simulating Application Logic} You can use JavaScript to generate mock data for your UI. @@ -56,7 +52,6 @@ Use the Simulink connector to connect a Simulink Simulation Model to your UI. Simulink is a MATLAB-based graphical programming environment for modeling, simulating, and analyzing multi-domain dynamic systems. - \endif \li \l{Using QML Modules with Plugins} diff --git a/doc/qtcreator/src/qtquick/qtquick-animation-overview.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-animation-overview.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-annotations.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-annotations.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-creating-ui-logic.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-creating-ui-logic.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-export.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-export.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-export.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-fonts.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-fonts.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-motion-design.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-motion-design.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-optimizing-designs.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-optimizing-designs.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-optimizing-designs.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-optimizing-designs.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-placeholder-data.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-placeholder-data.qdoc similarity index 95% rename from doc/qtcreator/src/qtquick/qtquick-placeholder-data.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-placeholder-data.qdoc index e684cfda634..237cfc67ef6 100644 --- a/doc/qtcreator/src/qtquick/qtquick-placeholder-data.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtquick-placeholder-data.qdoc @@ -25,17 +25,12 @@ /*! \page qtquick-placeholder-data.html - \previouspage studio-simulation-overview.html - \if defined(qtdesignstudio) \nextpage studio-javascript.html - \else - \nextpage creator-qml-modules-with-plugins.html - \endif \title Loading Placeholder Data - \QC supports views, models, and delegates, so that when you add + \QDS supports views, models, and delegates, so that when you add a Grid View, List View, or Path View component, the ListModel and the delegate component are added automatically. diff --git a/doc/qtcreator/src/qtquick/qtquick-production-quality-animation.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-production-quality-animation.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-production-quality-animation.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-production-quality-animation.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-prototyping.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-prototyping.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-prototyping.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-prototyping.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-uis.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-uis.qdoc rename to doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc diff --git a/doc/qtdesignstudio/src/overviews/studio-crashpad.qdoc b/doc/qtdesignstudio/src/overviews/studio-crashpad.qdoc new file mode 100644 index 00000000000..e195977f8b0 --- /dev/null +++ b/doc/qtdesignstudio/src/overviews/studio-crashpad.qdoc @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \page studio-crashpad.html + \previouspage studio-user-feedback.html + \nextpage studio-packaging.html + + \title Reporting Crashes + + You can enable \QDS to report crashes automatically. \QDS uses Google + Crashpad to collect crashes and report them to the Sentry backend storage + for processing. The purpose of Crashpad is to capture application state in + sufficient detail to allow developers to diagnose and, where possible, fix + the issue causing the crash. Crashpad may capture arbitrary contents from + the memory of a crashed process, including user sensitive information, URLs, + and other content provided by the users. The collected reports are used for + the sole purpose of fixing bugs. For more information on Crashpad, see the + \l {https://chromium.googlesource.com/crashpad/crashpad/+/master/doc/overview_design.md} + {documentation} by Google. For more information on processing and storing + of the collected data, see \l {https://sentry.io/security/} + {Security & Compliance} by Sentry. + + To enable sending crash reports, select \uicontrol Tools > \uicontrol + Options > \uicontrol Environment > \uicontrol System + (\uicontrol {Qt Design Studio} > \uicontrol Preferences > \uicontrol + Environment > \uicontrol System on \macos), and then select + \uicontrol {Enable crash reporting}. + + Since crash reports take up disk space, you may wish to remove them when + they are no longer needed. Select \uicontrol {Clear local crash reports} to + remove the crash report data. + + \image studio-crashpad-checkbox.png "Checkbox for enabling crash reporting" + + \note Crashpad is currently only supported on Windows and \macos. +*/ diff --git a/doc/qtdesignstudio/src/overviews/studio-user-feedback.qdoc b/doc/qtdesignstudio/src/overviews/studio-user-feedback.qdoc new file mode 100644 index 00000000000..463148a1c4b --- /dev/null +++ b/doc/qtdesignstudio/src/overviews/studio-user-feedback.qdoc @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \page studio-user-feedback.html + \previouspage collecting-usage-statistics.html + \nextpage studio-crashpad.html + + \title Collecting User Feedback + + A pop-up survey asking for your feedback will appear for some of the features + after you have been using them for some time. You will be asked to to rate + the usefulness of the feature on a scale of one to five stars. You must rate + the feature with at least one star if you wish to submit your rating. You + are also encouraged to give additional written feedback. After you select + \uicontrol Skip or \uicontrol Submit, the pop-up survey will not appear for + the same feature again. + + \image studio-feedback-popup.png "User feedback pop-up survey for Flow Editor" + + For the pop-up survey to appear, you must enable collecting statistics, and + also allow collecting \uicontrol {4 - Detailed usage statistics} in + \uicontrol Tools > \uicontrol Options > \uicontrol Telemetry > + \uicontrol {Usage Statistics} > \uicontrol {Telemetry mode}. + You can review the submitted user feedback in + \uicontrol Tools > \uicontrol Options > \uicontrol Telemetry > + \uicontrol {Usage Statistics} > \uicontrol {Collected Data} by selecting + \uicontrol {Qt Quick Designer Usage of views and actions} in + \uicontrol {Data sources}. +*/ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-packaging.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-packaging.qdoc index d7896770577..8f43fca3902 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-packaging.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-packaging.qdoc @@ -25,7 +25,7 @@ /*! \page studio-packaging.html - \previouspage creator-crashpad.html + \previouspage studio-crashpad.html \nextpage studio-developer-topics.html \title Packaging Applications diff --git a/doc/qtcreator/src/qtquick/qtdesignstudio-optimized-3d-scenes.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-optimized-3d-scenes.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtdesignstudio-optimized-3d-scenes.qdoc rename to doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-optimized-3d-scenes.qdoc diff --git a/doc/qtcreator/src/qtquick/creator-logical-operators.qdocinc b/doc/qtdesignstudio/src/views/creator-logical-operators.qdocinc similarity index 100% rename from doc/qtcreator/src/qtquick/creator-logical-operators.qdocinc rename to doc/qtdesignstudio/src/views/creator-logical-operators.qdocinc diff --git a/doc/qtcreator/src/qtquick/qtquick-adding-dynamics.qdoc b/doc/qtdesignstudio/src/views/qtquick-adding-dynamics.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-adding-dynamics.qdoc rename to doc/qtdesignstudio/src/views/qtquick-adding-dynamics.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-connection-editor-bindings.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-connection-editor-bindings.qdoc rename to doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-connection-editor-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-connection-editor-properties.qdoc rename to doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-connection-editor-signals.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-connection-editor-signals.qdoc rename to doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-connection-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-connection-editor.qdoc rename to doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-connection-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-view.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-connection-view.qdoc rename to doc/qtdesignstudio/src/views/qtquick-connection-view.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-curve-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-curve-editor.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-curve-editor.qdoc rename to doc/qtdesignstudio/src/views/qtquick-curve-editor.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-designer.qdoc b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-designer.qdoc rename to doc/qtdesignstudio/src/views/qtquick-designer.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-easing-curve-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-easing-curve-editor.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-easing-curve-editor.qdoc rename to doc/qtdesignstudio/src/views/qtquick-easing-curve-editor.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc rename to doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-library.qdoc b/doc/qtdesignstudio/src/views/qtquick-library.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-library.qdoc rename to doc/qtdesignstudio/src/views/qtquick-library.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-navigator.qdoc b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-navigator.qdoc rename to doc/qtdesignstudio/src/views/qtquick-navigator.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-properties-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-properties-view.qdoc rename to doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-properties.qdoc rename to doc/qtdesignstudio/src/views/qtquick-properties.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-states-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-states-view.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-states-view.qdoc rename to doc/qtdesignstudio/src/views/qtquick-states-view.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-states.qdoc b/doc/qtdesignstudio/src/views/qtquick-states.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-states.qdoc rename to doc/qtdesignstudio/src/views/qtquick-states.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-text-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-text-editor.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-text-editor.qdoc rename to doc/qtdesignstudio/src/views/qtquick-text-editor.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-timeline-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-timeline-view.qdoc rename to doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-timeline.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-timeline.qdoc rename to doc/qtdesignstudio/src/views/qtquick-timeline.qdoc diff --git a/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc similarity index 100% rename from doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc rename to doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc From 4544d891aa32255ec02385609c133c9685c9c72f Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 18 Oct 2021 11:46:46 +0200 Subject: [PATCH 083/117] GitHub Actions: Do not build qbs with Qt Creator Due to the recent changes that broke the MinGW 8.1 compilation and the qbs documentation python issues with both MinGW and MSVC. Change-Id: I401c2a1bd8f31de8fc7e44bb060247df75d9d1a0 Reviewed-by: Alessandro Portale --- .github/workflows/build_cmake.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 15cab0d19f0..3efc8a7b464 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -387,17 +387,6 @@ jobs: message(FATAL_ERROR "Failed to install dependencies") endif() endif() - find_package(Python3 REQUIRED COMPONENTS Interpreter) - # hack to replace 32-bit python found by this script with 64-bit one - # required for linking qtcreatorcdbext - string(REPLACE "x86" "x64" Python3_EXECUTABLE "${Python3_EXECUTABLE}") - execute_process( - COMMAND ${Python3_EXECUTABLE} -m pip install --user beautifulsoup4 lxml - RESULT_VARIABLE result - ) - if (NOT result EQUAL 0) - message(FATAL_ERROR "Failed to install python dependencies") - endif() - name: Build shell: cmake -P {0} @@ -480,6 +469,7 @@ jobs: --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=ccache --add-config=-DIDE_REVISION_URL=https://github.com/$ENV{GITHUB_REPOSITORY}/commits/$ENV{GITHUB_SHA} --zip-infix=-${{ matrix.config.artifact }}-${{ github.run_id }} + --no-qbs RESULT_VARIABLE result COMMAND_ECHO STDOUT OUTPUT_VARIABLE output From 719cdfd426c5f780dbb83e2ba0ca19858bc2ced7 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 15 Oct 2021 20:48:29 +0200 Subject: [PATCH 084/117] ProjectExplorer: Don't print out warnings when wizard.json parsing fails If plugins are disabled (e.g. Designer), some form page types (e.g. "Form") might be missing. Therefore the parsing of some wizard.json files will fail, which is expected. A recent patch added warning output for this case: Failed to create wizard: "wizard.json" Let's remove that, because that is the job of Qt Creator's Option: -customwizard-verbose Amends: 32799b3a7bd0cb8cd3da99c869649dab3be83634 Change-Id: Idda037c2e48ef290ff95754393572ec4309347b2 Reviewed-by: Artem Sokolovskii Reviewed-by: Samuel Ghinet Reviewed-by: Alessandro Portale --- src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index 431cbbf7756..1c8c710743c 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -400,14 +400,12 @@ QList JsonWizardFactory::createWizardFactories() .arg(currentFile.fileName()) .arg(line).arg(column) .arg(error.errorString())); - qWarning() << "Failed to parse wizard: " << currentFile.fileName(); continue; } if (!json.isObject()) { verboseLog.append(tr("* Did not find a JSON object in \"%1\".\n") .arg(currentFile.fileName())); - qWarning() << "Failed to parse wizard: " << currentFile.fileName(); continue; } @@ -425,7 +423,6 @@ QList JsonWizardFactory::createWizardFactories() JsonWizardFactory *factory = createWizardFactory(data, currentDir, &errorMessage); if (!factory) { verboseLog.append(tr("* Failed to create: %1\n").arg(errorMessage)); - qWarning() << "Failed to create wizard: " << currentFile.fileName(); continue; } From 6a6faec3b6344770052e353470d5e4d4d385e9d1 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 18 Oct 2021 17:47:22 +0300 Subject: [PATCH 085/117] QmlDesigner: Prevent error reporting when cancelling resouces dialog Task-number: QDS-5265 Change-Id: Ie2583fae8d1fd8564243499f30c6a2f82fd1dbbd Reviewed-by: Miikka Heikkinen Reviewed-by: Samuel Ghinet --- .../components/componentcore/modelnodeoperations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index ab2853354c8..10f1b4593d7 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -996,7 +996,7 @@ static bool addFilesToProject(const QStringList &fileNames, const QString &defau { QString directory = AddImagesDialog::getDirectory(fileNames, defaultDirectory); if (directory.isEmpty()) - return false; + return true; // cancelling the dialog is considered success bool allSuccessful = true; QList> copyList; From dc43cd52363e92a51c3a9d2b971d6a4c13a2fff5 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Wed, 13 Oct 2021 21:43:59 +0200 Subject: [PATCH 086/117] Doc: Remove SVG format from Photoshop Bridge docs Qt-Bridge plugin for Photoshop does not support SVG generation Task-number: QDS-4783 Change-Id: I527faef82ea889fede6309e1d66974e0cf41cca1 Reviewed-by: Leena Miettinen --- doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc index 87a9904cc88..4b45b87670a 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc @@ -127,7 +127,7 @@ \li Second level group layers are merged to their parent. \li Asset layers are exported as merged. \li Text layers are always exported as child items. - \li Images are exported in JPG, PNG, or SVG format, depending on your + \li Images are exported in PNG or JPG format, depending on your selection. \endlist From 4b245bbb49b219a22120a96137139509096a3b13 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 13 Oct 2021 10:47:08 +0300 Subject: [PATCH 087/117] DocumentManager: Check for permission change on every reload Fixes: QTCREATORBUG-22447 Change-Id: Iae26c01b97340ee4d6bb67a4655534130ba5537f Reviewed-by: Eike Ziller --- src/plugins/coreplugin/documentmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 6fa127e255b..d7d5f17d8f1 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -1186,10 +1186,10 @@ void DocumentManager::checkForReload() bool success = true; QString errorString; // we've got some modification + document->checkPermissions(); // check if it's contents or permissions: if (!type) { // Only permission change - document->checkPermissions(); success = true; // now we know it's a content change or file was removed } else if (defaultBehavior == IDocument::ReloadUnmodified && type == IDocument::TypeContents From e77e57420aa55c070615469dcc31ecb97da4e7de Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 14 Oct 2021 12:47:24 +0200 Subject: [PATCH 088/117] ClangCodeModel: Check for AST nodes from foreign files ... when highlighting with clangd. This can happen due to macro invocations or unusually placed includes. Task-number: QTCREATORBUG-26396 Change-Id: I471faee13c62fa511bdedfdd5b864327e858f6b8 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 92 ++++++++++++++++++--- 1 file changed, 80 insertions(+), 12 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 719c9e3352d..2b6044f3ac3 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -291,6 +291,58 @@ public: - openingQuoteOffset - 1); } + enum class FileStatus { Ours, Foreign, Mixed, Unknown }; + FileStatus fileStatus(const Utils::FilePath &thisFile) const + { + const Utils::optional arcanaString = arcana(); + if (!arcanaString) + return FileStatus::Unknown; + + // Example arcanas: + // "FunctionDecl 0x7fffb5d0dbd0 line:1:6 func 'void ()'" + // "VarDecl 0x7fffb5d0dcf0 /tmp/test.cpp:2:10 b 'bool' cinit" + // The second one is for a particularly silly construction where the RHS of an + // initialization comes from an included header. + const int openPos = arcanaString->indexOf('<'); + if (openPos == -1) + return FileStatus::Unknown; + const int closePos = arcanaString->indexOf('>', openPos + 1); + if (closePos == -1) + return FileStatus::Unknown; + bool hasOurs = false; + bool hasOther = false; + for (int startPos = openPos + 1; startPos < closePos;) { + int colon1Pos = arcanaString->indexOf(':', startPos); + if (colon1Pos == -1 || colon1Pos > closePos) + break; + if (Utils::HostOsInfo::isWindowsHost()) + colon1Pos = arcanaString->indexOf(':', colon1Pos + 1); + if (colon1Pos == -1 || colon1Pos > closePos) + break; + const int colon2Pos = arcanaString->indexOf(':', colon1Pos + 2); + if (colon2Pos == -1 || colon2Pos > closePos) + break; + const int line = subViewEnd(*arcanaString, colon1Pos + 1, colon2Pos).toString().toInt(); // TODO: Drop toString() once we require >= Qt 5.15 + if (line == 0) + break; + const QStringView fileOrLineString = subViewEnd(*arcanaString, startPos, colon1Pos); + if (fileOrLineString != QLatin1String("line")) { + if (Utils::FilePath::fromUserInput(fileOrLineString.toString()) == thisFile) + hasOurs = true; + else + hasOther = true; + } + const int commaPos = arcanaString->indexOf(',', colon2Pos + 2); + if (commaPos != -1) + startPos = commaPos + 2; + else + break; + } + if (hasOurs) + return hasOther ? FileStatus::Mixed : FileStatus::Ours; + return hasOther ? FileStatus::Foreign : FileStatus::Unknown; + } + // For debugging. void print(int indent = 0) const { @@ -2164,7 +2216,8 @@ class ExtraHighlightingResultsCollector { public: ExtraHighlightingResultsCollector(QFutureInterface &future, - HighlightingResults &results, const AstNode &ast, + HighlightingResults &results, + const Utils::FilePath &filePath, const AstNode &ast, const QTextDocument *doc, const QString &docContent); void collect(); @@ -2181,6 +2234,7 @@ private: QFutureInterface &m_future; HighlightingResults &m_results; + const Utils::FilePath m_filePath; const AstNode &m_ast; const QTextDocument * const m_doc; const QString &m_docContent; @@ -2246,6 +2300,7 @@ static QList cleanupDisabledCode(HighlightingResults &results, const } static void semanticHighlighter(QFutureInterface &future, + const Utils::FilePath &filePath, const QList &tokens, const QString &docContents, const AstNode &ast, const QPointer &widget, @@ -2377,7 +2432,7 @@ static void semanticHighlighter(QFutureInterface &future, if (widget && widget->textDocument()->document()->revision() == docRevision) widget->setIfdefedOutBlocks(ifdefedOutBlocks); }, Qt::QueuedConnection); - ExtraHighlightingResultsCollector(future, results, ast, &doc, docContents).collect(); + ExtraHighlightingResultsCollector(future, results, filePath, ast, &doc, docContents).collect(); if (!future.isCanceled()) { qCDebug(clangdLog) << "reporting" << results.size() << "highlighting results"; future.reportResults(QVector(results.cbegin(), @@ -2417,10 +2472,12 @@ void ClangdClient::Private::handleSemanticTokens(TextDocument *doc, IEditor * const editor = Utils::findOrDefault(EditorManager::visibleEditors(), [doc](const IEditor *editor) { return editor->document() == doc; }); const auto editorWidget = TextEditorWidget::fromEditor(editor); - const auto runner = [tokens, text = doc->document()->toPlainText(), ast, + const auto runner = [tokens, filePath = doc->filePath(), + text = doc->document()->toPlainText(), ast, w = QPointer(editorWidget), rev = doc->document()->revision(), clangdVersion = q->versionNumber()] { - return Utils::runAsync(semanticHighlighter, tokens, text, ast, w, rev, clangdVersion); + return Utils::runAsync(semanticHighlighter, filePath, tokens, text, ast, w, rev, + clangdVersion); }; if (isTesting) { @@ -2872,10 +2929,11 @@ MessageId ClangdClient::Private::getAndHandleAst(const TextDocOrFile &doc, ExtraHighlightingResultsCollector::ExtraHighlightingResultsCollector( QFutureInterface &future, HighlightingResults &results, - const AstNode &ast, const QTextDocument *doc, const QString &docContent) - : m_future(future), m_results(results), m_ast(ast), m_doc(doc), m_docContent(docContent) + const Utils::FilePath &filePath, const AstNode &ast, const QTextDocument *doc, + const QString &docContent) + : m_future(future), m_results(results), m_filePath(filePath), m_ast(ast), m_doc(doc), + m_docContent(docContent) { - } void ExtraHighlightingResultsCollector::collect() @@ -3320,12 +3378,22 @@ void ExtraHighlightingResultsCollector::visitNode(const AstNode &node) { if (m_future.isCanceled()) return; - collectFromNode(node); - const auto children = node.children(); - if (!children) + switch (node.fileStatus(m_filePath)) { + case AstNode::FileStatus::Foreign: return; - for (const AstNode &childNode : *children) - visitNode(childNode); + case AstNode::FileStatus::Ours: + case AstNode::FileStatus::Unknown: + collectFromNode(node); + [[fallthrough]]; + case ClangCodeModel::Internal::AstNode::FileStatus::Mixed: { + const auto children = node.children(); + if (!children) + return; + for (const AstNode &childNode : *children) + visitNode(childNode); + break; + } + } } } // namespace Internal From fc117972183250cea1e8e466123d97588dcdb4fb Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 19 Oct 2021 09:46:07 +0200 Subject: [PATCH 089/117] Editor: update ksyntaxhighlighting engine to v5.87.0 Change-Id: If9dab8b321799f0ce908c831e812c20301a714e1 Reviewed-by: Orgad Shaneh --- .../.git-blame-ignore-revs | 4 + .../3rdparty/syntax-highlighting/.gitignore | 11 +- .../syntax-highlighting/.gitlab-ci.yml | 5 + .../3rdparty/syntax-highlighting/.kde-ci.yml | 7 + .../syntax-highlighting/CMakeLists.txt | 4 +- .../3rdparty/syntax-highlighting/README.md | 43 +- .../autogenerated/autogenerated.pri | 3 +- .../ksyntaxhighlighting_version.h | 6 +- .../autogenerated/src/lib/WildcardMatcher | 1 + .../src/lib/ksyntaxhighlighting_export.h | 218 +++++++++ .../syntax-highlighting/data/CMakeLists.txt | 11 +- .../data/generators/cmake.xml.tpl | 2 +- .../data/generators/cmake.yaml | 231 +++++++++- .../data/generators/generate-doxygenlua.pl | 42 ++ .../data/generators/generate-php.pl | 1 + .../data/generators/generate-spdx-syntax.py | 67 +++ .../data/generators/spdx-comments.xml.tpl | 91 ++++ .../syntax-highlighting/data/syntax/bash.xml | 120 ++++- .../syntax-highlighting/data/syntax/cmake.xml | 155 ++++++- .../data/syntax/doxygen.xml | 4 +- .../syntax-highlighting/data/syntax/ini.xml | 19 +- .../syntax-highlighting/data/syntax/java.xml | 4 +- .../data/syntax/markdown.xml | 33 +- .../syntax-highlighting/data/syntax/perl.xml | 13 +- .../data/syntax/python.xml | 349 +++++++++++--- .../syntax-highlighting/data/syntax/xml.xml | 19 +- .../data/themes/ayu-dark.theme | 8 +- .../data/themes/ayu-light.theme | 8 +- .../data/themes/ayu-mirage.theme | 8 +- .../data/themes/breeze-dark.theme | 4 +- .../data/themes/breeze-light.theme | 4 +- .../data/themes/dracula.theme | 6 +- .../data/themes/falcon.theme | 184 ++++++++ .../data/themes/github-dark.theme | 6 +- .../data/themes/github-light.theme | 6 +- .../data/themes/gruvbox-dark.theme | 6 +- .../data/themes/gruvbox-light.theme | 6 +- .../data/themes/monokai.theme | 6 +- .../data/themes/nord.theme | 8 +- .../data/themes/printing.theme | 4 +- .../data/themes/solarized-dark.theme | 6 +- .../data/themes/solarized-light.theme | 6 +- .../data/themes/theme-data.qrc | 1 + .../data/themes/vim-dark.theme | 6 +- .../syntax-highlighting/metainfo.yaml | 2 +- .../src/cli/kate-syntax-highlighter.cpp | 14 +- .../src/indexer/CMakeLists.txt | 3 +- .../src/indexer/katehighlightingindexer.cpp | 434 +++++++++++++----- .../src/lib/CMakeLists.txt | 27 +- .../src/lib/abstracthighlighter.cpp | 50 +- .../src/lib/abstracthighlighter.h | 13 +- .../src/lib/ansihighlighter.cpp | 102 ++-- .../syntax-highlighting/src/lib/context.cpp | 17 +- .../src/lib/contextswitch.cpp | 9 +- .../src/lib/definition.cpp | 107 +++-- .../syntax-highlighting/src/lib/definition.h | 28 +- .../src/lib/definitiondownloader.cpp | 18 +- .../src/lib/definitionref_p.h | 4 +- .../syntax-highlighting/src/lib/format.cpp | 33 +- .../src/lib/htmlhighlighter.cpp | 39 +- .../src/lib/keywordlist.cpp | 31 +- .../src/lib/ksyntaxhighlighting_export.h | 34 -- .../src/lib/repository.cpp | 191 +++++--- .../syntax-highlighting/src/lib/repository.h | 10 + .../src/lib/repository_p.h | 2 +- .../syntax-highlighting/src/lib/rule.cpp | 291 +++++++----- .../syntax-highlighting/src/lib/rule_p.h | 74 +-- .../syntax-highlighting/src/lib/state.cpp | 3 +- .../src/lib/syntaxhighlighter.cpp | 56 ++- .../syntax-highlighting/src/lib/theme.h | 2 + .../syntax-highlighting/src/lib/themedata.cpp | 3 +- .../src/lib/wildcardmatcher.cpp | 21 +- .../src/lib/wildcardmatcher.h | 33 ++ .../src/lib/worddelimiters.cpp | 6 +- .../src/lib/worddelimiters_p.h | 2 +- .../syntax-highlighting/src/lib/xml_p.h | 2 +- .../syntax-highlighting.pro | 2 +- .../syntax-highlighting.qbs | 3 +- 78 files changed, 2607 insertions(+), 805 deletions(-) create mode 100644 src/libs/3rdparty/syntax-highlighting/.git-blame-ignore-revs create mode 100644 src/libs/3rdparty/syntax-highlighting/.gitlab-ci.yml create mode 100644 src/libs/3rdparty/syntax-highlighting/.kde-ci.yml create mode 100644 src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/WildcardMatcher create mode 100644 src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h create mode 100644 src/libs/3rdparty/syntax-highlighting/data/generators/generate-doxygenlua.pl create mode 100644 src/libs/3rdparty/syntax-highlighting/data/generators/generate-spdx-syntax.py create mode 100644 src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl create mode 100644 src/libs/3rdparty/syntax-highlighting/data/themes/falcon.theme delete mode 100644 src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h create mode 100644 src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.h diff --git a/src/libs/3rdparty/syntax-highlighting/.git-blame-ignore-revs b/src/libs/3rdparty/syntax-highlighting/.git-blame-ignore-revs new file mode 100644 index 00000000000..8b2ba6d3d5f --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# clang-format +56ed6f3f5f505eb0dbffc630729d67c3fb510546 +#clang-tidy +0960472cc3f57831a97697a4ae0cd139e2cc5551 diff --git a/src/libs/3rdparty/syntax-highlighting/.gitignore b/src/libs/3rdparty/syntax-highlighting/.gitignore index 4d50e82c2dc..a29428fe5e1 100644 --- a/src/libs/3rdparty/syntax-highlighting/.gitignore +++ b/src/libs/3rdparty/syntax-highlighting/.gitignore @@ -9,6 +9,11 @@ callgrind.* heaptrack.* /build*/ *.unc-backup* -.clang-format -.cmake/ -*.code-workspace \ No newline at end of file +/.clang-format +/.cmake/ +/*.code-workspace +/compile_commands.json +.clangd +.idea +/cmake-build* +.cache diff --git a/src/libs/3rdparty/syntax-highlighting/.gitlab-ci.yml b/src/libs/3rdparty/syntax-highlighting/.gitlab-ci.yml new file mode 100644 index 00000000000..8950fb6d61c --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/.gitlab-ci.yml @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2020 Volker Krause +# SPDX-License-Identifier: CC0-1.0 + +include: + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml diff --git a/src/libs/3rdparty/syntax-highlighting/.kde-ci.yml b/src/libs/3rdparty/syntax-highlighting/.kde-ci.yml new file mode 100644 index 00000000000..cf1d3363f9d --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/.kde-ci.yml @@ -0,0 +1,7 @@ +Dependencies: +- 'on': ['@all'] + 'require': + 'frameworks/extra-cmake-modules': '@same' + +Options: + test-before-installing: True diff --git a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt index 8dc268071a8..25f1af35730 100644 --- a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt @@ -10,11 +10,12 @@ add_qtc_library(KSyntaxHighlighting SHARED PUBLIC_INCLUDES src/lib autogenerated/src/lib - DEFINES KSYNTAXHIGHLIGHTING_LIBRARY + DEFINES KF5SyntaxHighlighting_EXPORTS DEPENDS Qt5::Network Qt5::Widgets SOURCES autogenerated/src/lib/ksyntaxhighlighting_logging.cpp autogenerated/src/lib/ksyntaxhighlighting_logging.h autogenerated/ksyntaxhighlighting_version.h + autogenerated/src/lib/ksyntaxhighlighting_export.h data/themes/theme-data.qrc @@ -29,7 +30,6 @@ add_qtc_library(KSyntaxHighlighting SHARED src/lib/format.cpp src/lib/format.h src/lib/format_p.h src/lib/htmlhighlighter.cpp src/lib/htmlhighlighter.h src/lib/keywordlist.cpp src/lib/keywordlist_p.h - src/lib/ksyntaxhighlighting_export.h src/lib/matchresult_p.h src/lib/repository.cpp src/lib/repository.h src/lib/repository_p.h src/lib/rule.cpp src/lib/rule_p.h diff --git a/src/libs/3rdparty/syntax-highlighting/README.md b/src/libs/3rdparty/syntax-highlighting/README.md index 2acff73b185..2e668dd3da6 100644 --- a/src/libs/3rdparty/syntax-highlighting/README.md +++ b/src/libs/3rdparty/syntax-highlighting/README.md @@ -23,6 +23,8 @@ It's meant as a building block for text editors as well as for simple highlighte text rendering (e.g. as HTML), supporting both integration with a custom editor as well as a ready-to-use QSyntaxHighlighter sub-class. +Besides a C++ API, a [QML API](@ref qml_api) is also provided. + ## Out of scope To not turn this into yet another text editor, the following things are considered @@ -46,7 +48,7 @@ in **data/syntax/** and have the **.xml** extension. Additional ones are picked up from the file system if present, so you can easily extend this by application-specific syntax definitions for example. -To install or test a syntax definiton file locally, place it in +To install or test a syntax definition file locally, place it in **org.kde.syntax-highlighting/syntax/**, which is located in your user directory. Usually it is: @@ -56,47 +58,56 @@ Usually it is: $HOME/.local/share/org.kde.syntax-highlighting/syntax/ - For Kate's Flatpak package - $HOME/.var/app/org.kde.kate/data/org.kde.syntax-highlighting/syntax/ + For Flatpak packages + $HOME/.var/app/package-name/data/org.kde.syntax-highlighting/syntax/ - For Kate's Snap package - $HOME/snap/kate/current/.local/share/org.kde.syntax-highlighting/syntax/ + For Snap packages + $HOME/snap/package-name/current/.local/share/org.kde.syntax-highlighting/syntax/ On Windows® %USERPROFILE%\AppData\Local\org.kde.syntax-highlighting\syntax\ + + On macOS® + $HOME/Library/Application Support/org.kde.syntax-highlighting/syntax/ + For more details, see ["The Highlight Definition XML Format" (Working with Syntax Highlighting, KDE Documentation)](https://docs.kde.org/?application=katepart&branch=trunk5&path=highlight.html#katehighlight-xml-format). -Also, in **data/schema/** there is a script to validate the syntax definiton XML +Also, in **data/schema/** there is a script to validate the syntax definition XML files. Use the command `validatehl.sh mySyntax.xml`. ## Color theme files -This library includes the color themes, the theme files use the **JSON** -format and are located in **data/themes/** with the **.theme** extension. +This library includes the color themes, which are documented +[here](https://docs.kde.org/?application=katepart&branch=trunk5&path=color-themes.html). +The color theme files use the JSON format and are located in **data/themes/** +with the **.theme** extension. Additional ones are also picked up from the file system if present, in the **org.kde.syntax-highlighting/themes/** folder of your user directory, -allowing you to easily add custom color theme files. -The location of **org.kde.syntax-highlighting/themes/** is the same +allowing you to easily add custom color theme files. This location is the same as shown in the table of the [previous section](#syntax-definition-files), replacing the **syntax** folder with **themes**. +For more details, see ["The Color Themes JSON Format" (Working with Color Themes, KDE Documentation)](https://docs.kde.org/?application=katepart&branch=trunk5&path=color-themes.html#color-themes-json). The [KTextEditor](https://api.kde.org/frameworks/ktexteditor/html/) library -(used by Kate, Kile and KDevelop, for example) provides -a user interface for editing and creating KSyntaxHighlighting color themes, including +(used by Kate, Kile and KDevelop, for example) provides a +[user interface](https://docs.kde.org/?application=katepart&branch=trunk5&path=color-themes.html#color-themes-gui) +for editing and creating KSyntaxHighlighting color themes, including a tool for exporting and importing the JSON theme files. + +Note that in KDE text editors, the KSyntaxHighlighting color themes are used +[since KDE Frameworks 5.75](https://kate-editor.org/post/2020/2020-09-13-kate-color-themes-5.75/), +released on October 10, 2020. Previously, Kate's color schemes +(KConfig based schema config) were used and are now deprecated. The tool **utils/schema-converter/** and the script **utils/kateschema_to_theme_converter.py** convert the old Kate schemas to KSyntaxHighlighting themes. -For more information, see: - -* [Kate - Color Themes with Frameworks 5.75 (Kate Editor Website)](https://kate-editor.org/post/2020/2020-09-13-kate-color-themes-5.75/) -* [Submit a KSyntaxHighlighting Color Theme (Kate Editor Website)](https://kate-editor.org/post/2020/2020-09-18-submit-a-ksyntaxhighlighting-color-theme/) +Also see ["Submit a KSyntaxHighlighting Color Theme" (Kate Editor Website)](https://kate-editor.org/post/2020/2020-09-18-submit-a-ksyntaxhighlighting-color-theme/). ## Build it diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/autogenerated.pri b/src/libs/3rdparty/syntax-highlighting/autogenerated/autogenerated.pri index aee620add95..1c540d45bed 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/autogenerated.pri +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/autogenerated.pri @@ -6,4 +6,5 @@ SOURCES += \ HEADERS += \ $$PWD/ksyntaxhighlighting_version.h \ - $$PWD/src/lib/ksyntaxhighlighting_logging.h + $$PWD/src/lib/ksyntaxhighlighting_logging.h \ + $$PWD/src/lib/ksyntaxhighlighting_export.h diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h index 32e5aa62a75..a8c5d74235a 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h @@ -3,10 +3,10 @@ #ifndef SyntaxHighlighting_VERSION_H #define SyntaxHighlighting_VERSION_H -#define SyntaxHighlighting_VERSION_STRING "5.80.0" +#define SyntaxHighlighting_VERSION_STRING "5.87.0" #define SyntaxHighlighting_VERSION_MAJOR 5 -#define SyntaxHighlighting_VERSION_MINOR 80 +#define SyntaxHighlighting_VERSION_MINOR 87 #define SyntaxHighlighting_VERSION_PATCH 0 -#define SyntaxHighlighting_VERSION ((5<<16)|(80<<8)|(0)) +#define SyntaxHighlighting_VERSION ((5<<16)|(87<<8)|(0)) #endif diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/WildcardMatcher b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/WildcardMatcher new file mode 100644 index 00000000000..ecea1b09bd9 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/WildcardMatcher @@ -0,0 +1 @@ +#include "wildcardmatcher.h" diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h new file mode 100644 index 00000000000..1213499635c --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h @@ -0,0 +1,218 @@ + +#ifndef KSYNTAXHIGHLIGHTING_EXPORT_H +#define KSYNTAXHIGHLIGHTING_EXPORT_H + +#include + +#ifdef KSYNTAXHIGHLIGHTING_STATIC_DEFINE +# define KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_NO_EXPORT +#else +# ifndef KSYNTAXHIGHLIGHTING_EXPORT +# ifdef KF5SyntaxHighlighting_EXPORTS + /* We are building this library */ +# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_EXPORT +# else + /* We are using this library */ +# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_IMPORT +# endif +# endif + +# ifndef KSYNTAXHIGHLIGHTING_NO_EXPORT +# define KSYNTAXHIGHLIGHTING_NO_EXPORT +# endif +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED __declspec(deprecated) +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT +# define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT +# define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# endif +#endif + +#define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) __declspec(deprecated(text)) + +#define ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) + +/* Take any defaults from group settings */ +#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) && !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +# ifdef KF_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# elif defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT +# endif +#endif +#if !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) && defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT +#endif + +#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) && !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) +# ifdef KF_NO_DEPRECATED_WARNINGS +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS +# elif defined(KF_DEPRECATED_WARNINGS_SINCE) +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE +# endif +#endif +#if !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) && defined(KF_DEPRECATED_WARNINGS_SINCE) +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE +#endif + +#if defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) +# undef KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT +#elif defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) +# define KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT +#else +# define KSYNTAXHIGHLIGHTING_DEPRECATED KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT +#endif + +/* No deprecated API had been removed from build */ +#define KSYNTAXHIGHLIGHTING_EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 + +#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 + +#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700 +#endif +#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE +# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# else +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700 +# endif +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0 +#endif + +#ifdef KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) (ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, 0) > KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +#else +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) 0 +#endif + +#if KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE >= 0x55700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) +#else +# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) +#endif +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5(minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_##minor(text) +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION(major, minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#major"."#minor". " text) +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#textmajor"."#textminor". " text) +// Not yet implemented for MSVC +#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION(major, minor, text) +#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) + +#endif /* KSYNTAXHIGHLIGHTING_EXPORT_H */ + + +#ifndef ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H +#define ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H + + +#define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) __declspec(deprecated(text)) + +#define ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) + +/* Take any defaults from group settings */ +#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) && !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +# ifdef KF_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# elif defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT +# endif +#endif +#if !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) && defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT +#endif + +#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) && !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) +# ifdef KF_NO_DEPRECATED_WARNINGS +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS +# elif defined(KF_DEPRECATED_WARNINGS_SINCE) +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE +# endif +#endif +#if !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) && defined(KF_DEPRECATED_WARNINGS_SINCE) +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE +#endif + +#if defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) +# undef KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT +#elif defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) +# define KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT +#else +# define KSYNTAXHIGHLIGHTING_DEPRECATED KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT +#endif + +/* No deprecated API had been removed from build */ +#define KSYNTAXHIGHLIGHTING_EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 + +#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 + +#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700 +#endif +#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE +# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# else +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700 +# endif +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0 +#endif + +#ifdef KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) (ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, 0) > KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +#else +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) 0 +#endif + +#if KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE >= 0x55700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) +#else +# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) +#endif +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5(minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_##minor(text) +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION(major, minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#major"."#minor". " text) +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#textmajor"."#textminor". " text) +// Not yet implemented for MSVC +#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION(major, minor, text) +#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) + + +#endif /* ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H */ diff --git a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt index 8b923c47952..acc2429ec84 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt @@ -38,8 +38,11 @@ generate_syntax_definition(generate-doxygenlua.pl doxygenlua.xml doxygen.xml) file(GLOB src_defs "${CMAKE_CURRENT_SOURCE_DIR}/syntax/*.xml") set(defs ${src_defs} ${gen_defs}) +# object library to make cross-folder dependencies work +add_library(SyntaxHighlightingData OBJECT) + # theme data resource -qt5_add_resources(themes_QRC ${CMAKE_CURRENT_SOURCE_DIR}/themes/theme-data.qrc) +target_sources(SyntaxHighlightingData PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/themes/theme-data.qrc) # do we want syntax files bundled in the library? if (QRC_SYNTAX) @@ -66,14 +69,10 @@ if (QRC_SYNTAX) ) set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" PROPERTIES SKIP_AUTOMOC ON) - # object library to make cross-folder dependencies work, themes + syntax files - add_library(SyntaxHighlightingData OBJECT ${themes_QRC} ${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp) + target_sources(SyntaxHighlightingData PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp) else() # install the syntax files as normal files into the prefix install (FILES ${defs} DESTINATION ${KDE_INSTALL_DATADIR}/org.kde.syntax-highlighting/syntax) - - # object library to make cross-folder dependencies work, only themes - add_library(SyntaxHighlightingData OBJECT ${themes_QRC}) endif() # set PIC to allow use in static and shared libs diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl index 8e8d37d266c..1c1a3da4ba2 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl @@ -22,7 +22,7 @@ @@ -172,6 +175,7 @@ target-properties: - EXCLUDE_FROM_ALL - EXCLUDE_FROM_DEFAULT_BUILD_ - EXCLUDE_FROM_DEFAULT_BUILD + - EXPORT_COMPILE_COMMANDS # Since 3.20 - EXPORT_NAME - EXPORT_PROPERTIES # Since 3.12 - FOLDER @@ -243,6 +247,7 @@ target-properties: - _CPPCHECK # Since 3.10 - _CPPLINT - _INCLUDE_WHAT_YOU_USE + - _LINKER_LAUNCHER # Sine 3.21 - _VISIBILITY_PRESET - LIBRARY_OUTPUT_DIRECTORY_ - LIBRARY_OUTPUT_DIRECTORY @@ -284,7 +289,6 @@ target-properties: - OBJCXX_STANDARD # Since 3.16 - OBJCXX_STANDARD_REQUIRED # Since 3.16 - OPTIMIZE_DEPENDENCIES # Since 3.19 - - OBJC_STANDARD - OSX_ARCHITECTURES_ - OSX_ARCHITECTURES - OSX_CURRENT_VERSION # Since 3.17 @@ -329,6 +333,7 @@ target-properties: - UNITY_BUILD_CODE_AFTER_INCLUDE # Since 3.16 - UNITY_BUILD_CODE_BEFORE_INCLUDE # Since 3.16 - UNITY_BUILD_MODE # Since 3.18 + - UNITY_BUILD_UNIQUE_ID # Since 3.20 - VERSION - VISIBILITY_INLINES_HIDDEN - VS_CONFIGURATION_TYPE @@ -372,6 +377,10 @@ target-properties: - WIN32_EXECUTABLE - WINDOWS_EXPORT_ALL_SYMBOLS - XCODE_ATTRIBUTE_ + - XCODE_EMBED__CODE_SIGN_ON_COPY # Since 3.20 + - XCODE_EMBED__PATH # Since 3.20 + - XCODE_EMBED__REMOVE_HEADERS_ON_COPY # Since 3.20 + - XCODE_EMBED_ # Since 3.20 - XCODE_EXPLICIT_FILE_TYPE - XCODE_GENERATE_SCHEME # Since 3.15 - XCODE_LINK_BUILD_PHASE_MODE # Since 3.19 @@ -572,6 +581,7 @@ generator-expressions: - TARGET_BUNDLE_DIR - TARGET_BUNDLE_CONTENT_DIR - TARGET_PROPERTY + - TARGET_RUNTIME_DLLS # Since 3.21 - INSTALL_PREFIX # Output-Related Expressions - TARGET_NAME @@ -581,6 +591,8 @@ generator-expressions: - MAKE_C_IDENTIFIER - TARGET_OBJECTS - SHELL_PATH + - OUTPUT_CONFIG # Since 3.20 + - COMMAND_CONFIG # Since 3.20 variables: # Variables that Provide Information @@ -687,6 +699,7 @@ variables: - CMAKE_XCODE_PLATFORM_TOOLSET - _BINARY_DIR - _DESCRIPTION # Since 3.12 + - _IS_TOP_LEVEL # Since 3.21 - _HOMEPAGE_URL # Since 3.12 - _SOURCE_DIR - _VERSION @@ -696,6 +709,7 @@ variables: - _VERSION_TWEAK - PROJECT_BINARY_DIR - PROJECT_DESCRIPTION # Since 3.9 + - PROJECT_IS_TOP_LEVEL # Since 3.21 - PROJECT_HOMEPAGE_URL # Since 3.12 - PROJECT_NAME - PROJECT_SOURCE_DIR @@ -819,6 +833,7 @@ variables: - ANDROID - APPLE - BORLAND + - CMAKE_ANDROID_NDK_VERSION # Since 3.20 - CMAKE_CL_64 - CMAKE_COMPILER_2005 - CMAKE_HOST_APPLE @@ -949,6 +964,9 @@ variables: - CMAKE__CPPCHECK # Since 3.10 - CMAKE__CPPLINT - CMAKE__INCLUDE_WHAT_YOU_USE + - CMAKE__LINKER_LAUNCHER # Sine 3.21 + - CMAKE__LINK_LIBRARY_FILE_FLAG # Sine 3.16 + - CMAKE__LINK_LIBRARY_FLAG # Sine 3.16 - CMAKE__VISIBILITY_PRESET - CMAKE_LIBRARY_OUTPUT_DIRECTORY - CMAKE_LIBRARY_OUTPUT_DIRECTORY_ @@ -1046,6 +1064,7 @@ variables: - CMAKE__ARCHIVE_APPEND - CMAKE__ARCHIVE_CREATE - CMAKE__ARCHIVE_FINISH + - CMAKE__BYTE_ORDER # Since 3.20 - CMAKE__COMPILER - CMAKE__COMPILER_EXTERNAL_TOOLCHAIN - CMAKE__COMPILER_ID @@ -1173,6 +1192,7 @@ variables: # Variables for CPack - CPACK_ABSOLUTE_DESTINATION_FILES - CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY + - CPACK_CUSTOM_INSTALL_VARIABLES # Since 3.21 - CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION - CPACK_INCLUDE_TOPLEVEL_DIRECTORY - CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS # Since 3.11 @@ -1182,32 +1202,57 @@ variables: - CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION # Variables for `find_package()` - PACKAGE_FIND_NAME - - PACKAGE_FIND_VERSION - - PACKAGE_FIND_VERSION_MAJOR - - PACKAGE_FIND_VERSION_MINOR - - PACKAGE_FIND_VERSION_PATCH - - PACKAGE_FIND_VERSION_TWEAK + # NOTE _VERSION and components already defined above, so skipped here - PACKAGE_FIND_VERSION_COUNT + - PACKAGE_FIND_VERSION_RANGE + - PACKAGE_FIND_VERSION_RANGE_MIN + - PACKAGE_FIND_VERSION_RANGE_MAX + - PACKAGE_FIND_VERSION_MIN + - PACKAGE_FIND_VERSION_MIN_MAJOR + - PACKAGE_FIND_VERSION_MIN_MINOR + - PACKAGE_FIND_VERSION_MIN_PATCH + - PACKAGE_FIND_VERSION_MIN_TWEAK + - PACKAGE_FIND_VERSION_MIN_COUNT + - PACKAGE_FIND_VERSION_MAX + - PACKAGE_FIND_VERSION_MAX_MAJOR + - PACKAGE_FIND_VERSION_MAX_MINOR + - PACKAGE_FIND_VERSION_MAX_PATCH + - PACKAGE_FIND_VERSION_MAX_TWEAK + - PACKAGE_FIND_VERSION_MAX_COUNT + - PACKAGE_FIND_VERSION_COMPLETE - PACKAGE_VERSION - PACKAGE_VERSION_EXACT - PACKAGE_VERSION_COMPATIBLE - PACKAGE_VERSION_UNSUITABLE - # NOTE _VERSION and components already defined above, so skipped here + # Package File Interface Variables - _FOUND - - _VERSION_COUNT - _FIND_REQUIRED - _FIND_QUIETLY - - _FIND_VERSION - - _FIND_VERSION_MAJOR - - _FIND_VERSION_MINOR - - _FIND_VERSION_PATCH - - _FIND_VERSION_TWEAK - - _FIND_VERSION_COUNT - - _FIND_VERSION_EXACT - - _FIND_COMPONENTS - - _FIND_REQUIRED_ - - _CONSIDERED_CONFIGS - - _CONSIDERED_VERSIONS + - _VERSION_COUNT + # NOTE _VERSION and components already defined above, so skipped here + - _FIND_VERSION_COUNT + - _FIND_VERSION_EXACT + - _FIND_COMPONENTS + - _FIND_REQUIRED_ + - _FIND_VERSION_RANGE + - _FIND_VERSION_RANGE_MIN + - _FIND_VERSION_RANGE_MAX + - _FIND_VERSION_MIN + - _FIND_VERSION_MIN_MAJOR + - _FIND_VERSION_MIN_MINOR + - _FIND_VERSION_MIN_PATCH + - _FIND_VERSION_MIN_TWEAK + - _FIND_VERSION_MIN_COUNT + - _FIND_VERSION_MAX + - _FIND_VERSION_MAX_MAJOR + - _FIND_VERSION_MAX_MINOR + - _FIND_VERSION_MAX_PATCH + - _FIND_VERSION_MAX_TWEAK + - _FIND_VERSION_MAX_COUNT + - _FIND_VERSION_COMPLETE + - _CONFIG + - _CONSIDERED_CONFIGS + - _CONSIDERED_VERSIONS - _ROOT # Since 3.12 # Other standard variables/patterns # - `try_run` @@ -1220,6 +1265,10 @@ variables: # - `cmake_parse_arguments` - _UNPARSED_ARGUMENTS - _KEYWORDS_MISSING_VALUES + # Variables that control `file(GET_RUNTIME_DEPENDENCIES)` behavior + - CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM + - CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL + - CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND # Well known CMake's official module's variables # - CheckCompilerFlag # - CheckCCompilerFlag @@ -1327,6 +1376,7 @@ variables: - CPACK_DEBIAN_PACKAGE_HOMEPAGE - CPACK_DEBIAN_PACKAGE_SHLIBDEPS - CPACK_DEBIAN__PACKAGE_SHLIBDEPS + - CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS # Since 3.20 - CPACK_DEBIAN_PACKAGE_DEBUG - CPACK_DEBIAN_PACKAGE_PREDEPENDS - CPACK_DEBIAN__PACKAGE_PREDEPENDS @@ -1364,6 +1414,7 @@ variables: - CPACK_DMG_SLA_DIR - CPACK_DMG_SLA_LANGUAGES - CPACK_DMG__FILE_NAME # Since 3.17 + - CPACK_DMG_FILESYSTEM # Since 3.21 - CPACK_COMMAND_HDIUTIL - CPACK_COMMAND_SETFILE - CPACK_COMMAND_REZ @@ -1389,6 +1440,7 @@ variables: - CPACK_IFW_PACKAGE_STYLE_SHEET # Since 3.15 - CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH - CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT + - CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST # Since 3.20 - CPACK_IFW_PACKAGE_TITLE_COLOR - CPACK_IFW_PACKAGE_START_MENU_DIRECTORY - CPACK_IFW_TARGET_DIRECTORY @@ -1443,6 +1495,9 @@ variables: - CPACK_NSIS_FINISH_TITLE_3LINES # Since 3.17 - CPACK_NSIS_MUI_HEADERIMAGE # Since 3.17 - CPACK_NSIS_MANIFEST_DPI_AWARE # Since 3.18 + - CPACK_NSIS_BRANDING_TEXT # Since 3.20 + - CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION # Since 3.20 + - CPACK_NSIS_EXECUTABLE # Since 3.21 # - CPackNuGet (since 3.12) - CPACK_NUGET_COMPONENT_INSTALL - CPACK_NUGET_PACKAGE_NAME @@ -1461,14 +1516,22 @@ variables: - CPACK_NUGET__PACKAGE_HOMEPAGE_URL - CPACK_NUGET_PACKAGE_LICENSEURL - CPACK_NUGET__PACKAGE_LICENSEURL + - CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION # Since 3.20 + - CPACK_NUGET__PACKAGE_LICENSE_EXPRESSION # Since 3.20 + - CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME # Since 3.20 + - CPACK_NUGET__PACKAGE_LICENSE_FILE_NAME # Since 3.20 - CPACK_NUGET_PACKAGE_ICONURL - CPACK_NUGET__PACKAGE_ICONURL + - CPACK_NUGET_PACKAGE_ICON # Since 3.20 + - CPACK_NUGET__PACKAGE_ICON # Since 3.20 - CPACK_NUGET_PACKAGE_DESCRIPTION_SUMMARY - CPACK_NUGET__PACKAGE_DESCRIPTION_SUMMARY - CPACK_NUGET_PACKAGE_RELEASE_NOTES - CPACK_NUGET__PACKAGE_RELEASE_NOTES - CPACK_NUGET_PACKAGE_COPYRIGHT - CPACK_NUGET__PACKAGE_COPYRIGHT + - CPACK_NUGET_PACKAGE_LANGUAGE # Since 3.20 + - CPACK_NUGET__PACKAGE_LANGUAGE # Since 3.20 - CPACK_NUGET_PACKAGE_TAGS - CPACK_NUGET__PACKAGE_TAGS - CPACK_NUGET_PACKAGE_DEPENDENCIES @@ -1617,6 +1680,7 @@ variables: - CPACK_PACKAGE_EXECUTABLES - CPACK_STRIP_FILES - CPACK_VERBATIM_VARIABLES + - CPACK_THREADS # Since 3.20 - CPACK_SOURCE_PACKAGE_FILE_NAME - CPACK_SOURCE_STRIP_FILES - CPACK_SOURCE_GENERATOR @@ -1754,12 +1818,19 @@ variables: - CMAKE_NO_ANSI_STRING_STREAM # - TestForSTDNamespace - CMAKE_NO_STD_NAMESPACE + # - UseJava + - CMAKE_JAVA_COMPILE_FLAGS + - CMAKE_JAVA_INCLUDE_PATH + - CMAKE_JNI_TARGET + - CMAKE_JAR_CLASSES_PREFIX # - UseSWIG + - UseSWIG_MODULE_VERSION # Since 3.12 - CMAKE_SWIG_FLAGS - CMAKE_SWIG_OUTDIR - SWIG_OUTFILE_DIR - SWIG_MODULE__EXTRA_DEPS - SWIG_SOURCE_FILE_EXTENSIONS # Since 3.14 + - SWIG_USE_SWIG_DEPENDENCIES # Since 3.20 deprecated-or-internal-variables: - CMAKE_HOME_DIRECTORY @@ -1784,6 +1855,10 @@ deprecated-or-internal-variables: - CPACK_TEMPORARY_DIRECTORY - CPACK_TOPLEVEL_DIRECTORY - CPACK_INSTALL_PREFIX + # Mentioned in `file(GET_RUNTIME_DEPENDENCIES)` docs + - CMAKE_OBJDUMP + # Mentioned in "Deprecated and Removed Features" of release notes 3.21 + - CMAKE_SYSTEM_ARCH # https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html # NOTE Added to syntax file version 14 at 3.15.0 version of CMake @@ -1801,6 +1876,7 @@ environment-variables: - CMAKE_MSVCIDE_RUN_PATH - CMAKE_NO_VERBOSE - CMAKE_OSX_ARCHITECTURES + - CMAKE_TOOLCHAIN_FILE # Since 3.21 - DESTDIR - LDFLAGS - MACOSX_DEPLOYMENT_TARGET @@ -1812,6 +1888,7 @@ environment-variables: - CC - CFLAGS - CSFLAGS + - CUDAARCHS # Since 3.20 - CUDACXX - CUDAFLAGS - CUDAHOSTCXX @@ -1896,6 +1973,55 @@ scripting-commands: - name: cmake_parse_arguments named-args: [PARSE_ARGV] + - + name: cmake_path # Since 3.20 + named-args: [ + # Decomposition + GET + , ROOT_NAME + , ROOT_DIRECTORY + , ROOT_PATH + , FILENAME + , EXTENSION + , LAST_ONLY + , STEM + , RELATIVE_PART + , PARENT_PATH + # Query + , HAS_ROOT_NAME + , HAS_ROOT_DIRECTORY + , HAS_ROOT_PATH + , HAS_FILENAME + , HAS_EXTENSION + , HAS_STEM + , HAS_RELATIVE_PART + , HAS_PARENT_PATH + , IS_ABSOLUTE + , IS_RELATIVE + , IS_PREFIX + , NORMALIZE + # Modification + , SET + , APPEND + , OUTPUT_VARIABLE + , APPEND_STRING + , REMOVE_FILENAME + , REPLACE_FILENAME + , REMOVE_EXTENSION + , REPLACE_EXTENSION + # Generation + , NORMAL_PATH + , RELATIVE_PATH + , BASE_DIRECTORY + , ABSOLUTE_PATH + # Native Conversion + , NATIVE_PATH + , CONVERT + , TO_CMAKE_PATH_LIST + , TO_NATIVE_PATH_LIST + # Hashing + , HASH + ] - name: cmake_policy named-args: [GET, SET, PUSH, POP, VERSION] @@ -1908,6 +2034,8 @@ scripting-commands: , NO_SOURCE_PERMISSIONS # Since 3.19 , "@ONLY" , NEWLINE_STYLE + , USE_SOURCE_PERMISSIONS # Since 3.20 + , FILE_PERMISSIONS # Since 3.20 ] special-args: [UNIX, DOS, WIN32, LF, CRLF] - @@ -2098,6 +2226,19 @@ scripting-commands: , SIZE # New sub-options since 3.16 , GET_RUNTIME_DEPENDENCIES + , RESOLVED_DEPENDENCIES_VAR + , UNRESOLVED_DEPENDENCIES_VAR + , EXECUTABLES + , LIBRARIES + , MODULES + , DIRECTORIES + , BUNDLE_EXECUTABLE + , PRE_INCLUDE_REGEXES + , PRE_EXCLUDE_REGEXES + , POST_INCLUDE_REGEXES + , POST_EXCLUDE_REGEXES + , POST_INCLUDE_FILES # Since 3.21 + , POST_EXCLUDE_FILES # Since 3.21 # New sub-options since 3.18 , ARCHIVE_CREATE , FILES @@ -2112,10 +2253,17 @@ scripting-commands: , ESCAPE_QUOTES , "@ONLY" , NEWLINE_STYLE - , CHMOD # Since 3.19 - , CHMOD_RECURSE # Since 3.19 - , REAL_PATH # Since 3.19 - , BASE_DIRECTORY # Since 3.19 + # New sub-options since 3.19 + , CHMOD + , CHMOD_RECURSE + , REAL_PATH + , BASE_DIRECTORY + # New sub-options since 3.21 + , COPY_FILE + , RESULT + , ONLY_IF_DIFFERENT + , EXPAND_TILDE + , NO_REPLACE ] special-args: [ UTF-8 @@ -2169,6 +2317,7 @@ scripting-commands: , PATHS , PATH_SUFFIXES , DOC + , NO_CACHE # Since 3.21 , REQUIRED # Since 3.18 , NO_DEFAULT_PATH , NO_PACKAGE_ROOT_PATH @@ -2189,6 +2338,7 @@ scripting-commands: , PATHS , PATH_SUFFIXES , DOC + , NO_CACHE # Since 3.21 , REQUIRED # Since 3.18 , NO_DEFAULT_PATH , NO_PACKAGE_ROOT_PATH @@ -2595,7 +2745,11 @@ project-commands: name: aux_source_directory - name: build_command - named-args: [CONFIGURATION, TARGET] + named-args: [ + CONFIGURATION + , PARALLEL_LEVEL # Since 3.21 + , TARGET + ] - name: create_test_sourcelist named-args: [EXTRA_INCLUDE, FUNCTION] @@ -2615,6 +2769,7 @@ project-commands: , CSharp , CXX , CUDA + , HIP # Since 3.21 , ISPC # Since 3.19 , Java , OBJC # Since 3.16 @@ -2664,6 +2819,7 @@ project-commands: , EXCLUDE_FROM_ALL , RENAME , OPTIONAL + , TYPE # Since 3.20 # Installing Targets , TARGETS , EXPORT @@ -2679,6 +2835,7 @@ project-commands: , INCLUDES , NAMELINK_ONLY , NAMELINK_SKIP + , RUNTIME_DEPENDENCIES # Since 3.21 # Installing Files , FILES , PROGRAMS @@ -2700,6 +2857,17 @@ project-commands: , FILE , EXPORT_ANDROID_MK , EXPORT_LINK_INTERFACE_LIBRARIES + # Installing Imported Runtime Artifacts (since 3.21) + , IMPORTED_RUNTIME_ARTIFACTS + , RUNTIME_DEPENDENCY_SET + # Installing Runtime Dependencies (since 3.21) + , PRE_INCLUDE_REGEXES + , PRE_EXCLUDE_REGEXES + , POST_INCLUDE_REGEXES + , POST_EXCLUDE_REGEXES + , POST_INCLUDE_FILES + , POST_EXCLUDE_FILES + , DIRECTORIES ] special-args: &valid_permissions [ OWNER_READ @@ -2740,6 +2908,7 @@ project-commands: , CSharp , CXX , CUDA + , HIP # Since 3.21 , ISPC # Since 3.19 , Java , OBJC # Since 3.16 @@ -2787,6 +2956,7 @@ project-commands: , cxx_std_14 , cxx_std_17 , cxx_std_20 # Since 3.12 + , cxx_std_23 # Since 3.20 , cxx_aggregate_default_initializers , cxx_alias_templates , cxx_alignas @@ -2848,6 +3018,8 @@ project-commands: , c_std_90 , c_std_99 , c_std_11 + , c_std_17 # Since 3.21 + , c_std_23 # Since 3.21 , c_function_prototypes , c_restrict , c_static_assert @@ -2858,13 +3030,21 @@ project-commands: , cuda_std_14 , cuda_std_17 , cuda_std_20 + , cuda_std_23 # Since 3.21 ] - name: target_compile_options named-args: &target_compile_options [BEFORE, INTERFACE, PUBLIC, PRIVATE] - name: target_include_directories - named-args: [BEFORE, SYSTEM, INTERFACE, PUBLIC, PRIVATE] + named-args: [ + AFTER # Since 3.20 + , BEFORE + , SYSTEM + , INTERFACE + , PUBLIC + , PRIVATE + ] - # Since 3.13 name: target_link_directories @@ -2910,6 +3090,7 @@ project-commands: , COMPILE_OUTPUT_VARIABLE , RUN_OUTPUT_VARIABLE , OUTPUT_VARIABLE + , WORKING_DIRECTORY # Since 3.20 , ARGS ] diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-doxygenlua.pl b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-doxygenlua.pl new file mode 100644 index 00000000000..ffc38ea17ea --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-doxygenlua.pl @@ -0,0 +1,42 @@ +#!/usr/bin/env perl +# SPDX-FileCopyrightText: 2020 Jonathan Poelen +# SPDX-License-Identifier: MIT + +my $file = ""; + +open(my $input, '<:encoding(UTF-8)', $ARGV[0]) + or die "Could not open file '$ARGV[0]': $!"; + +open(my $output, '>:encoding(UTF-8)', $ARGV[1]) + or die "Could not open file '$ARGV[1]': $!"; + +while (<$input>) +{ + $file .= $_; +} + +$warning = "\n\n\n"; +$first_context = " + + + + "; + +$file =~ s/\n\s*//gs; +$file =~ s/\n\s*/\n$first_context/s; +$file =~ s/\n[^\n]*?(?: ml_word|LineContinue)[^\n]+//gs; +$file =~ s/\/\/\//---/gs; +$file =~ s/\/\/!/--!/gs; + +$language = $file =~ s/.*?(]+?>).*/$1/sr; +$language =~ s/ name="[^"]+/ name="DoxygenLua/s; +$language =~ s/ extensions="[^"]+/ extensions="/s; +$language =~ s/ mimetype="[^"]+/ mimetype="/s; +$language =~ s/ priority="[^"]+"//s; +$version = $language =~ s/.*? version="([^"]+).*/$1/sr; +$version = $version+2; +$language =~ s/ version="[^"]+/ version="$version/s; +$file =~ s/]+?>/$warning\n$language/s; + +print $output $file; +print $output $warning; diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl index a3b20fb5546..a516332ef2f 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl @@ -45,6 +45,7 @@ if ($root == 1) $file =~ s/]+)section="[^"]*"/]+)extensions="[^"]*"/]+)mimetype="[^"]*"/]+)*/ +# SPDX-License-Identifier: MIT +# +# To install prerequisites: +# +# $ pip install --user click jinja2 +# +# To use: +# +# $ ./generate-spdx-syntax.py > ../syntax/spdx-comments.xml +# + +import json +import pathlib +import urllib.request + +import click +import jinja2 + + +def get_json(url): + with urllib.request.urlopen(url=url) as body: + return json.load(body) + + +@click.command() +@click.argument('template', type=click.File('r'), default='./spdx-comments.xml.tpl') +def cli(template): + + data = { + 'licenses': [ + *filter( + lambda l: not l['licenseId'].endswith('+') + , get_json(url='https://spdx.org/licenses/licenses.json')['licenses'] + ) + ] + , 'exceptions': [ + *filter( + lambda l: not l['licenseExceptionId'].endswith('+') + , get_json(url='https://spdx.org/licenses/exceptions.json')['exceptions'] + ) + ] + } + + env = jinja2.Environment( + keep_trailing_newline=True + ) + env.block_start_string = '' + env.variable_start_string = '' + env.comment_start_string = '' + + tpl = env.from_string(template.read()) + result = tpl.render(data) + print(result.strip(), end=None) + + +if __name__ == '__main__': + cli() + # TODO Handle execptions and show errors diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl new file mode 100644 index 00000000000..58cc80f960b --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl @@ -0,0 +1,91 @@ + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml index d7e4ed3d705..c7b21cb2a01 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml @@ -5,7 +5,7 @@ - |&;])"> + |&;)])"> |&;()"> @@ -18,6 +18,13 @@ + + + + + + + |&;{}\\`'"$"> @@ -28,9 +35,11 @@ + + ]> - + - + @@ -554,8 +563,8 @@ - - + + @@ -695,27 +704,30 @@ + - - - - - + + + + + + + + - - + @@ -724,6 +736,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1038,7 +1091,7 @@ - + @@ -1084,7 +1137,7 @@ - + @@ -1109,7 +1162,7 @@ - + @@ -1125,7 +1178,7 @@ - + @@ -1164,19 +1217,26 @@ + + + + + + + - @@ -1184,8 +1244,9 @@ + - + @@ -1216,11 +1277,18 @@ + + + + + + @@ -1305,7 +1373,7 @@ - + @@ -1321,6 +1389,18 @@ + + + + + + + + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml index 7f3920bfb64..d8676a250db 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml @@ -22,7 +22,7 @@ cmake_language cmake_minimum_required cmake_parse_arguments + cmake_path cmake_policy configure_file continue @@ -196,6 +197,47 @@ PARSE_ARGV + + ABSOLUTE_PATH + APPEND + APPEND_STRING + BASE_DIRECTORY + CONVERT + EXTENSION + FILENAME + GET + HASH + HAS_EXTENSION + HAS_FILENAME + HAS_PARENT_PATH + HAS_RELATIVE_PART + HAS_ROOT_DIRECTORY + HAS_ROOT_NAME + HAS_ROOT_PATH + HAS_STEM + IS_ABSOLUTE + IS_PREFIX + IS_RELATIVE + LAST_ONLY + NATIVE_PATH + NORMALIZE + NORMAL_PATH + OUTPUT_VARIABLE + PARENT_PATH + RELATIVE_PART + RELATIVE_PATH + REMOVE_EXTENSION + REMOVE_FILENAME + REPLACE_EXTENSION + REPLACE_FILENAME + ROOT_DIRECTORY + ROOT_NAME + ROOT_PATH + SET + STEM + TO_CMAKE_PATH_LIST + TO_NATIVE_PATH_LIST + GET POP @@ -211,8 +253,10 @@ @ONLY COPYONLY ESCAPE_QUOTES + FILE_PERMISSIONS NEWLINE_STYLE NO_SOURCE_PERMISSIONS + USE_SOURCE_PERMISSIONS CRLF @@ -291,6 +335,7 @@ ARCHIVE_CREATE ARCHIVE_EXTRACT BASE_DIRECTORY + BUNDLE_EXECUTABLE CHMOD CHMOD_RECURSE COMPRESSION @@ -300,13 +345,17 @@ CONFIGURE_DEPENDS CONTENT COPY + COPY_FILE DESTINATION + DIRECTORIES DIRECTORY DIRECTORY_PERMISSIONS DOWNLOAD ENCODING ESCAPE_QUOTES EXCLUDE + EXECUTABLES + EXPAND_TILDE EXPECTED_HASH EXPECTED_MD5 FILES @@ -327,6 +376,7 @@ INSTALL LENGTH_MAXIMUM LENGTH_MINIMUM + LIBRARIES LIMIT LIMIT_COUNT LIMIT_INPUT @@ -337,17 +387,26 @@ LOG MAKE_DIRECTORY MD5 + MODULES MTIME NETRC NETRC_FILE NEWLINE_CONSUME NEWLINE_STYLE NO_HEX_CONVERSION + NO_REPLACE NO_SOURCE_PERMISSIONS OFFSET + ONLY_IF_DIFFERENT OUTPUT PATTERN PERMISSIONS + POST_EXCLUDE_FILES + POST_EXCLUDE_REGEXES + POST_INCLUDE_FILES + POST_INCLUDE_REGEXES + PRE_EXCLUDE_REGEXES + PRE_INCLUDE_REGEXES READ READ_SYMLINK REAL_PATH @@ -358,6 +417,8 @@ REMOVE REMOVE_RECURSE RENAME + RESOLVED_DEPENDENCIES_VAR + RESULT RESULT_VARIABLE SHA1 SHA224 @@ -381,6 +442,7 @@ TOUCH_NOCREATE TO_CMAKE_PATH TO_NATIVE_PATH + UNRESOLVED_DEPENDENCIES_VAR UPLOAD USERPWD USE_SOURCE_PERMISSIONS @@ -433,6 +495,7 @@ DOC HINTS NAMES + NO_CACHE NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH @@ -451,6 +514,7 @@ HINTS NAMES NAMES_PER_DIR + NO_CACHE NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH @@ -495,6 +559,7 @@ DOC HINTS NAMES + NO_CACHE NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH @@ -513,6 +578,7 @@ HINTS NAMES NAMES_PER_DIR + NO_CACHE NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH @@ -883,6 +949,7 @@ CONFIGURATION + PARALLEL_LEVEL TARGET @@ -914,6 +981,7 @@ CUDA CXX Fortran + HIP ISPC Java OBJC @@ -951,6 +1019,7 @@ COMPONENT CONFIGURATIONS DESTINATION + DIRECTORIES DIRECTORY DIRECTORY_PERMISSIONS EXCLUDE @@ -963,6 +1032,7 @@ FILES_MATCHING FILE_PERMISSIONS FRAMEWORK + IMPORTED_RUNTIME_ARTIFACTS INCLUDES LIBRARY MESSAGE_NEVER @@ -974,6 +1044,12 @@ OPTIONAL PATTERN PERMISSIONS + POST_EXCLUDE_FILES + POST_EXCLUDE_REGEXES + POST_INCLUDE_FILES + POST_INCLUDE_REGEXES + PRE_EXCLUDE_REGEXES + PRE_INCLUDE_REGEXES PRIVATE_HEADER PROGRAMS PUBLIC_HEADER @@ -981,8 +1057,11 @@ RENAME RESOURCE RUNTIME + RUNTIME_DEPENDENCIES + RUNTIME_DEPENDENCY_SET SCRIPT TARGETS + TYPE USE_SOURCE_PERMISSIONS @@ -1028,6 +1107,7 @@ CUDA CXX Fortran + HIP ISPC Java NONE @@ -1068,6 +1148,8 @@ c_restrict c_static_assert c_std_11 + c_std_17 + c_std_23 c_std_90 c_std_99 c_variadic_macros @@ -1076,6 +1158,7 @@ cuda_std_14 cuda_std_17 cuda_std_20 + cuda_std_23 cxx_aggregate_default_initializers cxx_alias_templates cxx_alignas @@ -1126,6 +1209,7 @@ cxx_std_14 cxx_std_17 cxx_std_20 + cxx_std_23 cxx_std_98 cxx_strong_enums cxx_template_template_parameters @@ -1146,6 +1230,7 @@ PUBLIC + AFTER BEFORE INTERFACE PRIVATE @@ -1201,6 +1286,7 @@ OUTPUT_VARIABLE RUN_OUTPUT_VARIABLE RUN_RESULT_VAR + WORKING_DIRECTORY APPEND @@ -1342,6 +1428,7 @@ CMAKE_ANDROID_NDK_DEPRECATED_HEADERS CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION + CMAKE_ANDROID_NDK_VERSION CMAKE_ANDROID_PROCESS_MAX CMAKE_ANDROID_PROGUARD CMAKE_ANDROID_PROGUARD_CONFIG_PATH @@ -1497,6 +1584,9 @@ CMAKE_GENERATOR_NO_COMPILER_ENV CMAKE_GENERATOR_PLATFORM CMAKE_GENERATOR_TOOLSET + CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND + CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM + CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL CMAKE_GLOBAL_AUTOGEN_TARGET CMAKE_GLOBAL_AUTOGEN_TARGET_NAME CMAKE_GLOBAL_AUTORCC_TARGET @@ -1576,6 +1666,10 @@ CMAKE_ISPC_HEADER_DIRECTORY CMAKE_ISPC_HEADER_SUFFIX CMAKE_ISPC_INSTRUCTION_SETS + CMAKE_JAR_CLASSES_PREFIX + CMAKE_JAVA_COMPILE_FLAGS + CMAKE_JAVA_INCLUDE_PATH + CMAKE_JNI_TARGET CMAKE_JOB_POOLS CMAKE_JOB_POOL_COMPILE CMAKE_JOB_POOL_LINK @@ -1787,6 +1881,7 @@ CPACK_COMPONENTS_GROUPING CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY CPACK_CREATE_DESKTOP_LINKS + CPACK_CUSTOM_INSTALL_VARIABLES CPACK_CYGWIN_BUILD_SCRIPT CPACK_CYGWIN_PATCH_FILE CPACK_CYGWIN_PATCH_NUMBER @@ -1818,6 +1913,7 @@ CPACK_DEBIAN_PACKAGE_REPLACES CPACK_DEBIAN_PACKAGE_SECTION CPACK_DEBIAN_PACKAGE_SHLIBDEPS + CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS CPACK_DEBIAN_PACKAGE_SOURCE CPACK_DEBIAN_PACKAGE_SUGGESTS CPACK_DEBIAN_PACKAGE_VERSION @@ -1826,6 +1922,7 @@ CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK CPACK_DMG_DS_STORE CPACK_DMG_DS_STORE_SETUP_SCRIPT + CPACK_DMG_FILESYSTEM CPACK_DMG_FORMAT CPACK_DMG_SLA_DIR CPACK_DMG_SLA_LANGUAGES @@ -1865,6 +1962,7 @@ CPACK_IFW_PACKAGE_WINDOW_ICON CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH + CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST CPACK_IFW_PACKAGE_WIZARD_STYLE CPACK_IFW_PRODUCT_URL CPACK_IFW_REPOGEN_EXECUTABLE @@ -1880,12 +1978,15 @@ CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS CPACK_INSTALL_SCRIPTS CPACK_MONOLITHIC_INSTALL + CPACK_NSIS_BRANDING_TEXT + CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION CPACK_NSIS_COMPRESSOR CPACK_NSIS_CONTACT CPACK_NSIS_CREATE_ICONS_EXTRA CPACK_NSIS_DELETE_ICONS_EXTRA CPACK_NSIS_DISPLAY_NAME CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL + CPACK_NSIS_EXECUTABLE CPACK_NSIS_EXECUTABLES_DIRECTORY CPACK_NSIS_EXTRA_INSTALL_COMMANDS CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS @@ -1918,8 +2019,12 @@ CPACK_NUGET_PACKAGE_DESCRIPTION CPACK_NUGET_PACKAGE_DESCRIPTION_SUMMARY CPACK_NUGET_PACKAGE_HOMEPAGE_URL + CPACK_NUGET_PACKAGE_ICON CPACK_NUGET_PACKAGE_ICONURL + CPACK_NUGET_PACKAGE_LANGUAGE CPACK_NUGET_PACKAGE_LICENSEURL + CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION + CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME CPACK_NUGET_PACKAGE_NAME CPACK_NUGET_PACKAGE_OWNERS CPACK_NUGET_PACKAGE_RELEASE_NOTES @@ -2037,6 +2142,7 @@ CPACK_SOURCE_STRIP_FILES CPACK_STRIP_FILES CPACK_SYSTEM_NAME + CPACK_THREADS CPACK_TOPLEVEL_TAG CPACK_VERBATIM_VARIABLES CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION @@ -2180,12 +2286,23 @@ MSVC_TOOLSET_VERSION MSVC_VERSION PACKAGE_FIND_NAME - PACKAGE_FIND_VERSION + PACKAGE_FIND_VERSION_COMPLETE PACKAGE_FIND_VERSION_COUNT - PACKAGE_FIND_VERSION_MAJOR - PACKAGE_FIND_VERSION_MINOR - PACKAGE_FIND_VERSION_PATCH - PACKAGE_FIND_VERSION_TWEAK + PACKAGE_FIND_VERSION_MAX + PACKAGE_FIND_VERSION_MAX_COUNT + PACKAGE_FIND_VERSION_MAX_MAJOR + PACKAGE_FIND_VERSION_MAX_MINOR + PACKAGE_FIND_VERSION_MAX_PATCH + PACKAGE_FIND_VERSION_MAX_TWEAK + PACKAGE_FIND_VERSION_MIN + PACKAGE_FIND_VERSION_MIN_COUNT + PACKAGE_FIND_VERSION_MIN_MAJOR + PACKAGE_FIND_VERSION_MIN_MINOR + PACKAGE_FIND_VERSION_MIN_PATCH + PACKAGE_FIND_VERSION_MIN_TWEAK + PACKAGE_FIND_VERSION_RANGE + PACKAGE_FIND_VERSION_RANGE_MAX + PACKAGE_FIND_VERSION_RANGE_MIN PACKAGE_VERSION PACKAGE_VERSION_COMPATIBLE PACKAGE_VERSION_EXACT @@ -2196,6 +2313,7 @@ PROJECT_BINARY_DIR PROJECT_DESCRIPTION PROJECT_HOMEPAGE_URL + PROJECT_IS_TOP_LEVEL PROJECT_NAME PROJECT_SOURCE_DIR PROJECT_VERSION @@ -2206,8 +2324,10 @@ QTIFWDIR SWIG_OUTFILE_DIR SWIG_SOURCE_FILE_EXTENSIONS + SWIG_USE_SWIG_DEPENDENCIES THREADS_PREFER_PTHREAD_FLAG UNIX + UseSWIG_MODULE_VERSION WIN32 WINCE WINDOWS_PHONE @@ -2220,8 +2340,10 @@ CMAKE_HOME_DIRECTORY CMAKE_INTERNAL_PLATFORM_ABI CMAKE_NOT_USING_CONFIG_FLAGS + CMAKE_OBJDUMP CMAKE_SUPPRESS_DEVELOPER_ERRORS CMAKE_SUPPRESS_DEVELOPER_WARNINGS + CMAKE_SYSTEM_ARCH CMAKE_VS_INTEL_Fortran_PROJECT_VERSION CPACK_INSTALL_PREFIX CPACK_INSTALL_SCRIPT @@ -2248,12 +2370,14 @@ CMAKE_NO_VERBOSE CMAKE_OSX_ARCHITECTURES CMAKE_PREFIX_PATH + CMAKE_TOOLCHAIN_FILE CSFLAGS CTEST_INTERACTIVE_DEBUG_MODE CTEST_OUTPUT_ON_FAILURE CTEST_PARALLEL_LEVEL CTEST_PROGRESS_OUTPUT CTEST_USE_LAUNCHERS_DEFAULT + CUDAARCHS CUDACXX CUDAFLAGS CUDAHOSTCXX @@ -2326,6 +2450,7 @@ DEFINITIONS EXCLUDE_FROM_ALL IMPLICIT_DEPENDS_INCLUDE_TRANSFORM + IMPORTED_TARGETS INCLUDE_DIRECTORIES INCLUDE_REGULAR_EXPRESSION INTERPROCEDURAL_OPTIMIZATION @@ -2429,6 +2554,7 @@ ENABLE_EXPORTS EXCLUDE_FROM_ALL EXCLUDE_FROM_DEFAULT_BUILD + EXPORT_COMPILE_COMMANDS EXPORT_NAME EXPORT_PROPERTIES EchoString @@ -2554,6 +2680,7 @@ UNITY_BUILD_CODE_AFTER_INCLUDE UNITY_BUILD_CODE_BEFORE_INCLUDE UNITY_BUILD_MODE + UNITY_BUILD_UNIQUE_ID VERSION VISIBILITY_INLINES_HIDDEN VS_CONFIGURATION_TYPE @@ -2782,6 +2909,7 @@ TARGET_BUNDLE_DIR TARGET_BUNDLE_CONTENT_DIR TARGET_PROPERTY + TARGET_RUNTIME_DLLS INSTALL_PREFIX TARGET_NAME LINK_ONLY @@ -2790,6 +2918,8 @@ MAKE_C_IDENTIFIER TARGET_OBJECTS SHELL_PATH + OUTPUT_CONFIG + COMMAND_CONFIG @@ -2801,6 +2931,7 @@ + @@ -2950,6 +3081,14 @@ + + + + + + + + @@ -3860,7 +3999,7 @@ - + @@ -3894,7 +4033,7 @@ - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml index d7a53a167c0..5516c1454b7 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml @@ -1,12 +1,12 @@ + ]> - + @@ -34,15 +34,26 @@ - + + + - + + + + + - + + + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml index 6091cd4ee29..e71b1618a0d 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml @@ -7,7 +7,7 @@ ]> - + ACTIVE @@ -3732,6 +3732,7 @@ volatile + assert break case catch @@ -3760,6 +3761,7 @@ long short static + var void diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml index b35397af9c9..f03587977a4 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml @@ -90,7 +90,7 @@ ]> - + @@ -149,14 +149,33 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml index fdf2266558a..c9a60d64dbe 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml @@ -39,7 +39,7 @@ Enhance tr/// and y/// support. --> - + if @@ -92,7 +92,7 @@ + - * - + % || // @@ -420,7 +420,8 @@ - + + @@ -756,6 +757,12 @@ + + + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml index f1c89a54e41..676872f03fc 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml @@ -33,6 +33,10 @@ type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" --> + + + + ]> @@ -48,7 +52,7 @@ - + import @@ -86,10 +90,21 @@ try while with - yield async await + + yield + + yield from + + + match + case + __import__ abs @@ -366,89 +381,137 @@ + + + + - - - - - - - - - - - - - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + + + - + + + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + @@ -472,35 +535,53 @@ + + + + + + - + + + + - + + + + - - + + + + + - - + + + + + @@ -520,14 +601,25 @@ + + + + + + + + - + + @@ -542,107 +634,218 @@ Adding byte literals wouldn’t make the current 2⁴ into 2⁵ contexts, as there are no byte f-literals --> - + + + - + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + - + + + + + + + + + + + + + + + + + + - + + + + - - + + + + + + - + + + + - - + + + + + + + + + + + + + + + + + + + + + - + + + + - - + + + + + + - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + @@ -668,6 +871,8 @@ + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml index fbefcb6dad0..839e8f9162c 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml @@ -6,7 +6,7 @@ ]> - + @@ -16,13 +16,13 @@ + + - + - - @@ -70,13 +70,13 @@ - + - + @@ -116,7 +116,7 @@ - + @@ -131,7 +131,7 @@ - + @@ -140,7 +140,7 @@ - + @@ -175,6 +175,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-dark.theme index ebfde027973..fea8def01f3 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-dark.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Feb 22, 2021 (revision 3)", + "Last update: Jul 28, 2021 (revision 4)", "This file has been converted from: https://github.com/dempfi/ayu", "Also see: https://github.com/ayu-theme" ], @@ -11,7 +11,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "ayu Dark", - "revision": 3 + "revision": 4 }, "editor-colors": { "BackgroundColor": "#0a0e14", @@ -169,8 +169,8 @@ "text-color": "#39bae6" }, "VerbatimString": { - "selected-text-color": "#c2d94c", - "text-color": "#c2d94c" + "selected-text-color": "#99ca44", + "text-color": "#99ca44" }, "Warning": { "selected-text-color": "#f07178", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-light.theme index c93e414457e..30e119ed1b0 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-light.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Sep 21, 2020 (revision 2)", + "Last update: Jul 28, 2021 (revision 3)", "This file has been converted from: https://github.com/dempfi/ayu", "Also see: https://github.com/ayu-theme" ], @@ -11,7 +11,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "ayu Light", - "revision": 2 + "revision": 3 }, "editor-colors": { "BackgroundColor": "#fafafa", @@ -169,8 +169,8 @@ "text-color": "#55b4d4" }, "VerbatimString": { - "selected-text-color": "#86b300", - "text-color": "#86b300" + "selected-text-color": "#729800", + "text-color": "#729800" }, "Warning": { "selected-text-color": "#f07171", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-mirage.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-mirage.theme index e389ecf2981..005d6a0ad2a 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-mirage.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-mirage.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Feb 22, 2021 (revision 3)", + "Last update: Jul 28, 2021 (revision 4)", "This file has been converted from: https://github.com/dempfi/ayu", "Also see: https://github.com/ayu-theme" ], @@ -11,7 +11,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "ayu Mirage", - "revision": 3 + "revision": 4 }, "editor-colors": { "BackgroundColor": "#1f2430", @@ -169,8 +169,8 @@ "text-color": "#5ccfe6" }, "VerbatimString": { - "selected-text-color": "#bae67e", - "text-color": "#bae67e" + "selected-text-color": "#82e26a", + "text-color": "#82e26a" }, "Warning": { "selected-text-color": "#f28779", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-dark.theme index 712da4acc4a..1ad7fffee39 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-dark.theme @@ -5,7 +5,7 @@ "SPDX-FileCopyrightText: 2016 Dominik Haumann " ], "license": "SPDX-License-Identifier: MIT", - "revision" : 6, + "revision" : 7, "name" : "Breeze Dark" }, "text-styles": { @@ -149,7 +149,7 @@ "editor-colors": { "BackgroundColor" : "#232629", "CodeFolding" : "#224e65", - "BracketMatching" : "#323030", + "BracketMatching" : "#8e44ad", "CurrentLine" : "#2A2E32", "IconBorder" : "#31363b", "IndentationLine" : "#3a3f44", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-light.theme index 7d0116bea95..6dee8dd7777 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-light.theme @@ -5,7 +5,7 @@ "SPDX-FileCopyrightText: 2016 Dominik Haumann " ], "license": "SPDX-License-Identifier: MIT", - "revision" : 8, + "revision" : 9, "name" : "Breeze Light" }, "text-styles": { @@ -70,7 +70,7 @@ "selected-text-color" : "#9c0e0e" }, "VerbatimString" : { - "text-color" : "#bf0303", + "text-color" : "#e31616", "selected-text-color" : "#9c0e0e" }, "SpecialString" : { diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/dracula.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/dracula.theme index 93b1833334f..b388396050c 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/dracula.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/dracula.theme @@ -570,7 +570,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "Dracula", - "revision": 7 + "revision": 8 }, "text-styles": { "Alert": { @@ -694,8 +694,8 @@ "text-color": "#8be9fd" }, "VerbatimString": { - "selected-text-color": "#f1fa8c", - "text-color": "#f1fa8c" + "selected-text-color": "#d7e60a", + "text-color": "#d7e60a" }, "Warning": { "selected-text-color": "#ff5555", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/falcon.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/falcon.theme new file mode 100644 index 00000000000..1ebf8c69466 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/falcon.theme @@ -0,0 +1,184 @@ +{ + "_comments": [ + "A theme focused on ergonomics, using the 3 digit Tango color palette" + ], + "metadata": { + "name": "Falcon", + "revision": 4, + "license": "SPDX-License-Identifier: MIT", + "copyright": [ "SPDX-FileCopyrightText: 2021 Alberto Salvia Novella " ] + }, + "custom-styles": { + "Bash": { + "Normal Text": { + "text-color": "#bbbbbb" + } + } + }, + "editor-colors": { + "BackgroundColor": "#223333", + "BracketMatching": "#555555", + "CodeFolding": "#224488", + "CurrentLine": "#555555", + "CurrentLineNumber": "#bbbbbb", + "IconBorder": "#223333", + "IndentationLine": "#888888", + "LineNumbers": "#888888", + "MarkBookmark": "#7799cc", + "MarkBreakpointActive": "#ffaa33", + "MarkBreakpointDisabled": "#aa77aa", + "MarkBreakpointReached": "#449900", + "MarkError": "#ef2929", + "MarkExecution": "#888888", + "MarkWarning": "#aa77aa", + "ModifiedLines": "#aa0000", + "ReplaceHighlight": "#224488", + "SavedLines": "#449900", + "SearchHighlight": "#224488", + "Separator": "#555753", + "SpellChecking": "#ef2929", + "TabMarker": "#555555", + "TemplateBackground": "#223333", + "TemplateFocusedPlaceholder": "#23321a", + "TemplatePlaceholder": "#23321a", + "TemplateReadOnlyPlaceholder": "#451e1a", + "TextSelection": "#3366aa", + "WordWrapMarker": "#555753" + }, + "text-styles": { + "Alert": { + "background-color": "#320000", + "bold": true, + "selected-text-color": "#ffaa33", + "text-color": "#ee2222" + }, + "Annotation": { + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "Attribute": { + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "BaseN": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "BuiltIn": { + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "Char": { + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "Comment": { + "selected-text-color": "#eeeeec", + "text-color": "#888888" + }, + "CommentVar": { + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "Constant": { + "bold": true, + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "ControlFlow": { + "bold": true, + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "DataType": { + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "DecVal": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "Documentation": { + "selected-text-color": "#eeeeee", + "text-color": "#d3d7cf" + }, + "Error": { + "selected-text-color": "#ffaa33", + "text-color": "#ee2222", + "underline": true + }, + "Extension": { + "bold": true, + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "Float": { + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "Function": { + "bold": true, + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "Import": { + "selected-text-color": "#88ee33", + "text-color": "#88ee33" + }, + "Information": { + "selected-text-color": "#eeeeee", + "text-color": "#ddddcc" + }, + "Keyword": { + "bold": true, + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "Normal": { + "selected-text-color": "#eeeeee", + "text-color": "#ddddcc" + }, + "Operator": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "Others": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "Preprocessor": { + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "RegionMarker": { + "background-color": "#0d1932", + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "SpecialChar": { + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "SpecialString": { + "selected-text-color": "#eeeeee", + "text-color": "#ddddcc" + }, + "String": { + "selected-text-color": "#eeeeee", + "text-color": "#ddddcc" + }, + "Variable": { + "bold": true, + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "VerbatimString": { + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "Warning": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + } + } +} diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/github-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/github-dark.theme index 313e99f0529..a6996385327 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/github-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/github-dark.theme @@ -82,7 +82,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "GitHub Dark", - "revision": 2 + "revision": 3 }, "text-styles": { "Alert": { @@ -205,8 +205,8 @@ "text-color": "#ffab70" }, "VerbatimString": { - "selected-text-color": "#9ecbff", - "text-color": "#9ecbff" + "selected-text-color": "#41a0ff", + "text-color": "#41a0ff" }, "Warning": { "selected-text-color": "#ff5555", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/github-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/github-light.theme index 5f465c653ce..ed56418fde3 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/github-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/github-light.theme @@ -82,7 +82,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "GitHub Light", - "revision": 2 + "revision": 3 }, "text-styles": { "Alert": { @@ -205,8 +205,8 @@ "text-color": "#e36209" }, "VerbatimString": { - "selected-text-color": "#032f62", - "text-color": "#032f62" + "selected-text-color": "#034c95", + "text-color": "#034c95" }, "Warning": { "selected-text-color": "#ff5555", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-dark.theme index 66c6c9afb7e..0e006ab46e0 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-dark.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Sep 17, 2020 (revision 2)", + "Last update: Jul 28, 2021 (revision 3)", "This file has been converted from: https://github.com/morhetz/gruvbox" ], "metadata" : { @@ -10,7 +10,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name" : "gruvbox Dark", - "revision" : 2 + "revision" : 3 }, "text-styles": { "Normal" : { @@ -73,7 +73,7 @@ "selected-text-color" : "#b8bb26" }, "VerbatimString" : { - "text-color" : "#98971a", + "text-color" : "#848216", "selected-text-color" : "#b8bb26" }, "SpecialString" : { diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-light.theme index 6038c70e94f..937a43d084c 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-light.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Sep 17, 2020 (revision 2)", + "Last update: Jul 28, 2021 (revision 3)", "This file has been converted from: https://github.com/morhetz/gruvbox" ], "metadata" : { @@ -10,7 +10,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name" : "gruvbox Light", - "revision" : 2 + "revision" : 3 }, "text-styles": { "Normal" : { @@ -73,7 +73,7 @@ "selected-text-color" : "#79740e" }, "VerbatimString" : { - "text-color" : "#98971a", + "text-color" : "#848216", "selected-text-color" : "#79740e" }, "SpecialString" : { diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/monokai.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/monokai.theme index 3df8e66c005..e0026ca3b3e 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/monokai.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/monokai.theme @@ -259,7 +259,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "Monokai", - "revision": 5 + "revision": 6 }, "text-styles": { "Alert": { @@ -383,8 +383,8 @@ "text-color": "#f8f8f2" }, "VerbatimString": { - "selected-text-color": "#e6db74", - "text-color": "#e6db74" + "selected-text-color": "#d8c72c", + "text-color": "#d8c72c" }, "Warning": { "selected-text-color": "#ff5555", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/nord.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/nord.theme index 6ad4d82e43c..dbe44d9b096 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/nord.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/nord.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Sep 21, 2020 (revision 2)", + "Last update: Jul 28, 2020 (revision 3)", "This theme has been adapted from: https://www.nordtheme.com" ], "metadata": { @@ -11,7 +11,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "Nord", - "revision": 2 + "revision": 3 }, "editor-colors": { "BackgroundColor": "#2e3440", @@ -170,8 +170,8 @@ "text-color": "#5e81ac" }, "VerbatimString": { - "selected-text-color": "#a3be8c", - "text-color": "#a3be8c" + "selected-text-color": "#8dae70", + "text-color": "#8dae70" }, "Warning": { "selected-text-color": "#bf616a", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/printing.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/printing.theme index 26d779582d7..49bbe6419f0 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/printing.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/printing.theme @@ -5,7 +5,7 @@ "SPDX-FileCopyrightText: 2016 Dominik Haumann " ], "license": "SPDX-License-Identifier: MIT", - "revision" : 4, + "revision" : 5, "name" : "Printing" }, "text-styles": { @@ -69,7 +69,7 @@ "selected-text-color" : "#9c0e0e" }, "VerbatimString" : { - "text-color" : "#bf0303", + "text-color" : "#ea0404", "selected-text-color" : "#9c0e0e" }, "SpecialString" : { diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-dark.theme index b8d13b31d3c..1fe48bacd0b 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-dark.theme @@ -9,7 +9,7 @@ "SPDX-FileCopyrightText: 2018 Andrew Crouthamel " ], "license": "SPDX-License-Identifier: MIT", - "revision" : 5, + "revision" : 6, "name" : "Solarized Dark" }, "text-styles": { @@ -70,8 +70,8 @@ "selected-text-color" : "#2aa198" }, "VerbatimString" : { - "text-color" : "#2aa198", - "selected-text-color" : "#2aa198" + "text-color" : "#23877e", + "selected-text-color" : "#23877e" }, "SpecialString" : { "text-color" : "#dc322f", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-light.theme index a532b128f8d..51c76faaec4 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-light.theme @@ -9,7 +9,7 @@ "SPDX-FileCopyrightText: 2018 Andrew Crouthamel " ], "license": "SPDX-License-Identifier: MIT", - "revision" : 4, + "revision" : 5, "name" : "Solarized Light" }, "text-styles": { @@ -73,8 +73,8 @@ "selected-text-color" : "#2aa198" }, "VerbatimString" : { - "text-color" : "#2aa198", - "selected-text-color" : "#2aa198" + "text-color" : "#23837a", + "selected-text-color" : "#23837a" }, "SpecialString" : { "text-color" : "#dc322f", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc b/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc index fe0a1627be6..cf9d658c824 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc @@ -9,6 +9,7 @@ ayu-light.theme ayu-mirage.theme dracula.theme + falcon.theme github-dark.theme github-light.theme gruvbox-dark.theme diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/vim-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/vim-dark.theme index 1a2c7785ac7..d039822cae3 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/vim-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/vim-dark.theme @@ -5,7 +5,7 @@ "SPDX-FileCopyrightText: 2020 Nibaldo González " ], "license": "SPDX-License-Identifier: MIT", - "revision" : 3, + "revision" : 4, "name" : "Vim Dark" }, "text-styles": { @@ -70,8 +70,8 @@ "selected-text-color" : "#ff54ff" }, "VerbatimString" : { - "text-color" : "#ff54ff", - "selected-text-color" : "#ff54ff" + "text-color" : "#f000f0", + "selected-text-color" : "#f000f0" }, "SpecialString" : { "text-color" : "#ff5500", diff --git a/src/libs/3rdparty/syntax-highlighting/metainfo.yaml b/src/libs/3rdparty/syntax-highlighting/metainfo.yaml index 7a3220a31e1..a82f7a986d4 100644 --- a/src/libs/3rdparty/syntax-highlighting/metainfo.yaml +++ b/src/libs/3rdparty/syntax-highlighting/metainfo.yaml @@ -6,7 +6,7 @@ platforms: - name: Linux - name: FreeBSD - name: Windows - - name: MacOSX + - name: macOS - name: Android portingAid: false deprecated: false diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp index a009c4f2591..749123aa545 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp @@ -30,10 +30,11 @@ static void applyHighlighter(Highlighter &highlighter, const QCommandLineOption &outputName, const Ts &...highlightParams) { - if (parser.isSet(outputName)) + if (parser.isSet(outputName)) { highlighter.setOutputFile(parser.value(outputName)); - else + } else { highlighter.setOutputFile(stdout); + } if (fromFileName) { highlighter.highlightFile(inFileName, highlightParams...); @@ -126,8 +127,9 @@ int main(int argc, char **argv) } if (parser.isSet(listThemes)) { - for (const auto &theme : repo.themes()) + for (const auto &theme : repo.themes()) { std::cout << qPrintable(theme.name()) << std::endl; + } return 0; } @@ -158,9 +160,10 @@ int main(int argc, char **argv) if (!def.isValid()) { /* see if it's a extension instead */ def = repo.definitionForFileName(QLatin1String("f.") + syntax); - if (!def.isValid()) + if (!def.isValid()) { /* see if it's a filename instead */ def = repo.definitionForFileName(syntax); + } } } } else if (fromFileName) { @@ -177,8 +180,9 @@ int main(int argc, char **argv) QString outputFormat = parser.value(outputFormatOption); if (0 == outputFormat.compare(QLatin1String("html"), Qt::CaseInsensitive)) { QString title; - if (parser.isSet(titleOption)) + if (parser.isSet(titleOption)) { title = parser.value(titleOption); + } HtmlHighlighter highlighter; highlighter.setDefinition(def); diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt index 508cd276cc3..4a84696ad91 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt @@ -28,7 +28,8 @@ elseif(CMAKE_CROSSCOMPILING) else() # host build add_executable(katehighlightingindexer katehighlightingindexer.cpp ../lib/worddelimiters.cpp) - if(Qt5XmlPatterns_FOUND) + ecm_mark_nongui_executable(katehighlightingindexer) + if(Qt5XmlPatterns_FOUND AND NOT ECM_ENABLE_SANITIZERS) target_link_libraries(katehighlightingindexer Qt5::XmlPatterns) else() target_link_libraries(katehighlightingindexer Qt5::Core) diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp index 86b3a38b12d..789089625b8 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp @@ -31,7 +31,8 @@ using KSyntaxHighlighting::Xml::attrToBool; class HlFilesChecker { public: - void setDefinition(const QStringRef &verStr, const QString &filename, const QString &name) + template + void setDefinition(const T &verStr, const QString &filename, const QString &name) { m_currentDefinition = &*m_definitions.insert(name, Definition{}); m_currentDefinition->languageName = name; @@ -93,6 +94,12 @@ public: continue; } + auto markAsUsedContext = [](ContextName &ContextName) { + if (!ContextName.stay && ContextName.context) { + ContextName.context->isOnlyIncluded = false; + } + }; + QMutableMapIterator contextIt(contexts); while (contextIt.hasNext()) { contextIt.next(); @@ -100,12 +107,21 @@ public: resolveContextName(definition, context, context.lineEndContext, context.line); resolveContextName(definition, context, context.lineEmptyContext, context.line); resolveContextName(definition, context, context.fallthroughContext, context.line); + markAsUsedContext(context.lineEndContext); + markAsUsedContext(context.lineEmptyContext); + markAsUsedContext(context.fallthroughContext); for (auto &rule : context.rules) { + rule.parentContext = &context; resolveContextName(definition, context, rule.context, rule.line); + if (rule.type != Context::Rule::Type::IncludeRules) { + markAsUsedContext(rule.context); + } } } - definition.firstContext = &*definition.contexts.find(definition.firstContextName); + auto *firstContext = &*definition.contexts.find(definition.firstContextName); + firstContext->isOnlyIncluded = false; + definition.firstContext = firstContext; } resolveIncludeRules(); @@ -118,6 +134,7 @@ public: const auto usedContexts = extractUsedContexts(); QMap maxVersionByDefinitions; + QMap unreachableIncludedRules; QMapIterator def(m_definitions); while (def.hasNext()) { @@ -135,14 +152,7 @@ public: QSet referencedKeywords; QSet usedAttributeNames; success = checkKeywordsList(definition, referencedKeywords) && success; - success = checkContexts(definition, referencedKeywords, usedAttributeNames, usedContexts) && success; - - // search for non-existing or unreferenced keyword lists. - for (const auto &keywords : definition.keywordsList) { - if (!referencedKeywords.contains(&keywords)) { - qWarning() << filename << "line" << keywords.line << "unused keyword:" << keywords.name; - } - } + success = checkContexts(definition, referencedKeywords, usedAttributeNames, usedContexts, unreachableIncludedRules) && success; // search for non-existing itemDatas. const auto invalidNames = usedAttributeNames - definition.itemDatas.styleNames; @@ -159,6 +169,56 @@ public: } } + QMutableMapIterator unreachableIncludedRuleIt(unreachableIncludedRules); + while (unreachableIncludedRuleIt.hasNext()) { + unreachableIncludedRuleIt.next(); + IncludedRuleUnreachableBy &unreachableRulesBy = unreachableIncludedRuleIt.value(); + if (unreachableRulesBy.alwaysUnreachable) { + auto *rule = unreachableIncludedRuleIt.key(); + + if (!rule->parentContext->isOnlyIncluded) { + continue; + } + + // remove duplicates rules + QSet rules; + auto &unreachableBy = unreachableRulesBy.unreachableBy; + unreachableBy.erase(std::remove_if(unreachableBy.begin(), + unreachableBy.end(), + [&](const RuleAndInclude &ruleAndInclude) { + if (rules.contains(ruleAndInclude.rule)) { + return true; + } + rules.insert(ruleAndInclude.rule); + return false; + }), + unreachableBy.end()); + + QString message; + message.reserve(128); + for (auto &ruleAndInclude : std::as_const(unreachableBy)) { + message += QStringLiteral("line "); + message += QString::number(ruleAndInclude.rule->line); + message += QStringLiteral(" ["); + message += ruleAndInclude.rule->parentContext->name; + if (rule->filename != ruleAndInclude.rule->filename) { + message += QStringLiteral(" ("); + message += ruleAndInclude.rule->filename; + message += QLatin1Char(')'); + } + if (ruleAndInclude.includeRules) { + message += QStringLiteral(" via line "); + message += QString::number(ruleAndInclude.includeRules->line); + } + message += QStringLiteral("], "); + } + message.chop(2); + + qWarning() << rule->filename << "line" << rule->line << "no IncludeRule can reach this rule, hidden by" << message; + success = false; + } + } + return success; } @@ -176,7 +236,7 @@ private: int popCount = 0; bool stay = false; - const Context *context = nullptr; + Context *context = nullptr; }; struct Parser { @@ -185,12 +245,13 @@ private: QXmlStreamAttribute &attr; bool success; - //! Read a string type attribute, \c sucess = \c false when \p str is not empty + //! Read a string type attribute, \c success = \c false when \p str is not empty //! \return \c true when attr.name() == attrName, otherwise false bool extractString(QString &str, const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } str = attr.value().toString(); if (str.isEmpty()) { @@ -201,24 +262,26 @@ private: return true; } - //! Read a bool type attribute, \c sucess = \c false when \p xmlBool is not \c XmlBool::Unspecified. + //! Read a bool type attribute, \c success = \c false when \p xmlBool is not \c XmlBool::Unspecified. //! \return \c true when attr.name() == attrName, otherwise false bool extractXmlBool(XmlBool &xmlBool, const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } xmlBool = attr.value().isNull() ? XmlBool::Unspecified : attrToBool(attr.value()) ? XmlBool::True : XmlBool::False; return true; } - //! Read a positive integer type attribute, \c sucess = \c false when \p positive is already greater than or equal to 0 + //! Read a positive integer type attribute, \c success = \c false when \p positive is already greater than or equal to 0 //! \return \c true when attr.name() == attrName, otherwise false bool extractPositive(int &positive, const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } bool ok = true; positive = attr.value().toInt(&ok); @@ -231,12 +294,13 @@ private: return true; } - //! Read a color, \c sucess = \c false when \p color is already greater than or equal to 0 + //! Read a color, \c success = \c false when \p color is already greater than or equal to 0 //! \return \c true when attr.name() == attrName, otherwise false bool checkColor(const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } const auto value = attr.value().toString(); if (value.isEmpty() /*|| QColor(value).isValid()*/) { @@ -247,16 +311,17 @@ private: return true; } - //! Read a QChar, \c sucess = \c false when \p c is not \c '\0' or does not have one char + //! Read a QChar, \c success = \c false when \p c is not \c '\0' or does not have one char //! \return \c true when attr.name() == attrName, otherwise false bool extractChar(QChar &c, const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } - if (attr.value().size() == 1) + if (attr.value().size() == 1) { c = attr.value()[0]; - else { + } else { c = QLatin1Char('_'); qWarning() << filename << "line" << xml.lineNumber() << attrName << "must contain exactly one char:" << attr.value(); success = false; @@ -268,8 +333,9 @@ private: //! \return parsing status when \p isExtracted is \c true, otherwise \c false bool checkIfExtracted(bool isExtracted) { - if (isExtracted) + if (isExtracted) { return success; + } qWarning() << filename << "line" << xml.lineNumber() << "unknown attribute:" << attr.name(); return false; @@ -400,18 +466,19 @@ private: QString additionalDeliminator; QString weakDeliminator; - // rules included by IncludeRules + // rules included by IncludeRules (without IncludeRule) QVector includedRules; // IncludeRules included by IncludeRules QSet includedIncludeRules; + Context const *parentContext = nullptr; + QString filename; bool parseElement(const QString &filename, QXmlStreamReader &xml) { this->filename = filename; - line = xml.lineNumber(); using Pair = QPair; @@ -579,6 +646,8 @@ private: }; int line; + // becomes false when a context refers to it + bool isOnlyIncluded = true; QString name; QString attribute; ContextName lineEndContext; @@ -723,8 +792,9 @@ private: { Context context; m_success = context.parseElement(m_currentDefinition->filename, xml) && m_success; - if (m_currentDefinition->firstContextName.isEmpty()) + if (m_currentDefinition->firstContextName.isEmpty()) { m_currentDefinition->firstContextName = context.name; + } if (m_currentDefinition->contexts.contains(context.name)) { qWarning() << m_currentDefinition->filename << "line" << xml.lineNumber() << "duplicate context:" << context.name; m_success = false; @@ -784,6 +854,7 @@ private: m_success = false; continue; } + if (rule.context.popCount) { qWarning() << definition.filename << "line" << rule.line << "IncludeRules with #pop prefix"; m_success = false; @@ -794,6 +865,8 @@ private: continue; } + // resolve includedRules and includedIncludeRules + usedContexts.clear(); usedContexts.insert(rule.context.context); contexts.clear(); @@ -866,11 +939,27 @@ private: return usedContexts; } + struct RuleAndInclude { + const Context::Rule *rule; + const Context::Rule *includeRules; + + explicit operator bool() const + { + return rule; + } + }; + + struct IncludedRuleUnreachableBy { + QVector unreachableBy; + bool alwaysUnreachable = true; + }; + //! Check contexts and rules bool checkContexts(const Definition &definition, QSet &referencedKeywords, QSet &usedAttributeNames, - const QSet &usedContexts) const + const QSet &usedContexts, + QMap &unreachableIncludedRules) const { bool success = true; @@ -892,16 +981,18 @@ private: success = false; } - if (!context.attribute.isEmpty()) + if (!context.attribute.isEmpty()) { usedAttributeNames.insert({context.attribute, context.line}); + } success = checkfallthrough(definition, context) && success; - success = checkUreachableRules(definition.filename, context) && success; + success = checkUreachableRules(definition.filename, context, unreachableIncludedRules) && success; success = suggestRuleMerger(definition.filename, context) && success; for (const auto &rule : context.rules) { - if (!rule.attribute.isEmpty()) + if (!rule.attribute.isEmpty()) { usedAttributeNames.insert({rule.attribute, rule.line}); + } success = checkLookAhead(rule) && success; success = checkStringDetect(rule) && success; success = checkAnyChar(rule) && success; @@ -954,9 +1045,14 @@ private: return false; } +#define REG_ESCAPE_CHAR R"(\\(?:[^0BDPSWbdpswoux]|x[0-9a-fA-F]{2}|x\{[0-9a-fA-F]+\}|0\d\d|o\{[0-7]+\}|u[0-9a-fA-F]{4}))" +#define REG_CHAR "(?:" REG_ESCAPE_CHAR "|\\[(?:" REG_ESCAPE_CHAR "|.)\\]|[^[.^])" + // is RangeDetect - static const QRegularExpression isRange(QStringLiteral( - R"(^(\\(?:[^0BDPSWbdpswoux]|x[0-9a-fA-F]{2}|x\{[0-9a-fA-F]+\}|0\d\d|o\{[0-7]+\}|u[0-9a-fA-F]{4})|[^[.]|\[[^].\\]\])(?:\.|\[^\1\])\*[?*]?\1$)")); + static const QRegularExpression isRange(QStringLiteral("^\\^?" REG_CHAR "(?:" + "\\.\\*[?*]?" REG_CHAR "|" + "\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?*]?\\1" + ")$")); if (( rule.lookAhead == XmlBool::True || rule.minimal == XmlBool::True || rule.string.contains(QStringLiteral(".*?")) @@ -967,11 +1063,21 @@ private: return false; } + // is LineContinue + static const QRegularExpression isLineContinue(QStringLiteral("^\\^?" REG_CHAR "\\$$")); + if (reg.contains(isLineContinue)) { + auto extra = (reg[0] == QLatin1Char('^')) ? "with column=\"0\"" : ""; + qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by LineContinue:" << rule.string << extra; + return false; + } + // replace \c, \xhhh, \x{hhh...}, \0dd, \o{ddd}, \uhhhh, with _ - static const QRegularExpression sanitize1( - QStringLiteral(R"(\\(?:[^0BDPSWbdpswoux]|x[0-9a-fA-F]{2}|x\{[0-9a-fA-F]+\}|0\d\d|o\{[0-7]+\}|u[0-9a-fA-F]{4}))")); + static const QRegularExpression sanitize1(QStringLiteral(REG_ESCAPE_CHAR)); reg.replace(sanitize1, QStringLiteral("_")); +#undef REG_CHAR +#undef REG_ESCAPE_CHAR + // use minimal or lazy operator static const QRegularExpression isMinimal(QStringLiteral( R"([.][*+][^][?+*()|$]*$)")); @@ -1008,8 +1114,9 @@ private: char const *extraMsg = rule.string.contains(QLatin1Char('^')) ? "+ column=\"0\" or firstNonSpace=\"1\"" : ""; qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by StringDetect / Detect2Chars / DetectChar" << extraMsg << ":" << rule.string; - if (len != reg.size()) + if (len != reg.size()) { qWarning() << rule.filename << "line" << rule.line << "insensitive=\"1\" missing:" << rule.string; + } return false; } @@ -1019,8 +1126,8 @@ private: // (^sas*) -> ok // (^sa|s*) -> ko // (^(sa|s*)) -> ok - auto first = qAsConst(reg).begin(); - auto last = qAsConst(reg).end(); + auto first = std::as_const(reg).begin(); + auto last = std::as_const(reg).end(); int depth = 0; while (QLatin1Char('(') == *first) { @@ -1066,8 +1173,8 @@ private: // add ^ with column=0 if (rule.column == 0 && !rule.isDotRegex) { bool hasStartOfLine = false; - auto first = qAsConst(reg).begin(); - auto last = qAsConst(reg).end(); + auto first = std::as_const(reg).begin(); + auto last = std::as_const(reg).end(); for (; first != last; ++first) { if (*first == QLatin1Char('^')) { hasStartOfLine = true; @@ -1306,8 +1413,9 @@ private: //! Search for additionalDeliminator/weakDeliminator which has no effect. bool checkDelimiters(const Definition &definition, const Context::Rule &rule) const { - if (rule.additionalDeliminator.isEmpty() && rule.weakDeliminator.isEmpty()) + if (rule.additionalDeliminator.isEmpty() && rule.weakDeliminator.isEmpty()) { return true; + } bool success = true; @@ -1472,16 +1580,39 @@ private: //! - StringDetect, WordDetect, RegExpr with as prefix Detect2Chars or other strings //! - duplicate rule (Int, Float, keyword with same String, etc) //! - Rule hidden by a dot regex - bool checkUreachableRules(const QString &filename, const Context &context) const + bool checkUreachableRules(const QString &filename, + const Context &context, + QMap &unreachableIncludedRules) const { - struct RuleAndInclude { - const Context::Rule *rule; - const Context::Rule *includeRules; + if (context.isOnlyIncluded) { + return true; + } - explicit operator bool() const + struct Rule4 { + RuleAndInclude setRule(const Context::Rule &rule, const Context::Rule *includeRules = nullptr) { - return rule; + auto set = [&](RuleAndInclude &ruleAndInclude) { + auto old = ruleAndInclude; + ruleAndInclude = {&rule, includeRules}; + return old; + }; + + if (rule.firstNonSpace == XmlBool::True) { + return set(firstNonSpace); + } else if (rule.column == 0) { + return set(column0); + } else if (rule.column > 0) { + return set(columnGreaterThan0[rule.column]); + } else { + return set(normal); + } } + + private: + RuleAndInclude normal; + RuleAndInclude column0; + QMap columnGreaterThan0; + RuleAndInclude firstNonSpace; }; // Associate QChar with RuleAndInclude @@ -1489,8 +1620,9 @@ private: /// Search RuleAndInclude associated with @p c. RuleAndInclude find(QChar c) const { - if (c.unicode() < 128) + if (c.unicode() < 128) { return m_asciiMap[c.unicode()]; + } auto it = m_utf8Map.find(c); return it == m_utf8Map.end() ? RuleAndInclude{nullptr, nullptr} : it.value(); } @@ -1517,10 +1649,11 @@ private: /// Associates @p c with a rule. void append(QChar c, const Context::Rule &rule, const Context::Rule *includeRule = nullptr) { - if (c.unicode() < 128) + if (c.unicode() < 128) { m_asciiMap[c.unicode()] = {&rule, includeRule}; - else + } else { m_utf8Map[c] = {&rule, includeRule}; + } } /// Associates each character of @p s with a rule. @@ -1549,13 +1682,15 @@ private: // Char4Tables::char is always added. CharTableArray(Char4Tables &tables, const Context::Rule &rule) { - if (rule.firstNonSpace == XmlBool::True) + if (rule.firstNonSpace == XmlBool::True) { appendTable(tables.charsFirstNonSpace); + } - if (rule.column == 0) + if (rule.column == 0) { appendTable(tables.charsColumn0); - else if (rule.column > 0) + } else if (rule.column > 0) { appendTable(tables.charsColumnGreaterThan0[rule.column]); + } appendTable(tables.chars); } @@ -1572,8 +1707,9 @@ private: RuleAndInclude find(QChar c) const { for (int i = 0; i < m_size; ++i) { - if (auto ruleAndInclude = m_charTables[i]->find(c)) + if (auto ruleAndInclude = m_charTables[i]->find(c)) { return ruleAndInclude; + } } return RuleAndInclude{nullptr, nullptr}; } @@ -1621,9 +1757,19 @@ private: int m_size = 0; }; + struct ObservableRule { + const Context::Rule *rule; + const Context::Rule *includeRules; + + bool hasResolvedIncludeRules() const + { + return rule == includeRules; + } + }; + // Iterates over all the rules, including those in includedRules struct RuleIterator { - RuleIterator(const QVector &rules, const Context::Rule &endRule) + RuleIterator(const QVector &rules, const ObservableRule &endRule) : m_end(&endRule - rules.data()) , m_rules(rules) { @@ -1635,7 +1781,7 @@ private: // if in includedRules if (m_includedRules) { ++m_i2; - if (m_i2 != m_rules[m_i].includedRules.size()) { + if (m_i2 != m_includedRules->size()) { return (*m_includedRules)[m_i2]; } ++m_i; @@ -1643,10 +1789,10 @@ private: } // if is a includedRules - while (m_i < m_end && m_rules[m_i].type == Context::Rule::Type::IncludeRules) { - if (m_rules[m_i].includedRules.size()) { + while (m_i < m_end && m_rules[m_i].rule->type == Context::Rule::Type::IncludeRules) { + if (!m_rules[m_i].includeRules && m_rules[m_i].rule->includedRules.size()) { m_i2 = 0; - m_includedRules = &m_rules[m_i].includedRules; + m_includedRules = &m_rules[m_i].rule->includedRules; return (*m_includedRules)[m_i2]; } ++m_i; @@ -1654,7 +1800,7 @@ private: if (m_i < m_end) { ++m_i; - return &m_rules[m_i - 1]; + return m_rules[m_i - 1].rule; } return nullptr; @@ -1663,14 +1809,14 @@ private: /// \return current IncludeRules or nullptr const Context::Rule *currentIncludeRules() const { - return m_includedRules ? &m_rules[m_i] : nullptr; + return m_includedRules ? m_rules[m_i].rule : m_rules[m_i].includeRules; } private: int m_i = 0; int m_i2; int m_end; - const QVector &m_rules; + const QVector &m_rules; const QVector *m_includedRules = nullptr; }; @@ -1680,20 +1826,24 @@ private: void append(const Context::Rule &rule, const Context::Rule *includedRule) { auto array = extractDotRegexes(rule); - if (array[0]) + if (array[0]) { *array[0] = {&rule, includedRule}; - if (array[1]) + } + if (array[1]) { *array[1] = {&rule, includedRule}; + } } /// Search dot regex which hides @p rule RuleAndInclude find(const Context::Rule &rule) { auto array = extractDotRegexes(rule); - if (array[0]) + if (array[0]) { return *array[0]; - if (array[1]) + } + if (array[1]) { return *array[1]; + } return RuleAndInclude{}; } @@ -1707,13 +1857,15 @@ private: if (rule.firstNonSpace != XmlBool::True && rule.column == -1) { ret[0] = &dotRegex; } else { - if (rule.firstNonSpace == XmlBool::True) + if (rule.firstNonSpace == XmlBool::True) { ret[0] = &dotRegexFirstNonSpace; + } - if (rule.column == 0) + if (rule.column == 0) { ret[1] = &dotRegexColumn0; - else if (rule.column > 0) + } else if (rule.column > 0) { ret[1] = &dotRegexColumnGreaterThan0[rule.column]; + } } return ret; @@ -1734,23 +1886,44 @@ private: // characters of LineContinue Char4Tables lineContinueChars; - RuleAndInclude intRule{}; - RuleAndInclude floatRule{}; - RuleAndInclude hlCCharRule{}; - RuleAndInclude hlCOctRule{}; - RuleAndInclude hlCHexRule{}; - RuleAndInclude hlCStringCharRule{}; + Rule4 intRule{}; + Rule4 floatRule{}; + Rule4 hlCCharRule{}; + Rule4 hlCOctRule{}; + Rule4 hlCHexRule{}; + Rule4 hlCStringCharRule{}; + Rule4 detectIdentifierRule{}; // Contains includedRules and included includedRules QMap includeContexts; DotRegex dotRegex; + QVector observedRules; + observedRules.reserve(context.rules.size()); for (const Context::Rule &rule : context.rules) { + const Context::Rule *includeRule = nullptr; + if (rule.type == Context::Rule::Type::IncludeRules) { + auto *context = rule.context.context; + if (context && context->isOnlyIncluded) { + includeRule = &rule; + } + } + + observedRules.push_back({&rule, includeRule}); + if (includeRule) { + for (const Context::Rule *rule2 : rule.includedRules) { + observedRules.push_back({rule2, includeRule}); + } + } + } + + for (auto &observedRule : observedRules) { + const Context::Rule &rule = *observedRule.rule; bool isUnreachable = false; QVector unreachableBy; - // declare rule as unreacheable if ruleAndInclude is not empty + // declare rule as unreachable if ruleAndInclude is not empty auto updateUnreachable1 = [&](RuleAndInclude ruleAndInclude) { if (ruleAndInclude) { isUnreachable = true; @@ -1758,7 +1931,7 @@ private: } }; - // declare rule as unreacheable if ruleAndIncludes is not empty + // declare rule as unreachable if ruleAndIncludes is not empty auto updateUnreachable2 = [&](const QVector &ruleAndIncludes) { if (!ruleAndIncludes.isEmpty()) { isUnreachable = true; @@ -1810,43 +1983,42 @@ private: // check if hidden by DetectChar/AnyChar case Context::Rule::Type::HlCChar: updateUnreachable1(CharTableArray(detectChars, rule).find(QLatin1Char('\''))); - updateUnreachable1(hlCCharRule); - hlCCharRule = {&rule, nullptr}; + updateUnreachable1(hlCCharRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::HlCHex: updateUnreachable1(CharTableArray(detectChars, rule).find(QLatin1Char('0'))); - updateUnreachable1(hlCHexRule); - hlCHexRule = {&rule, nullptr}; + updateUnreachable1(hlCHexRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::HlCOct: updateUnreachable1(CharTableArray(detectChars, rule).find(QLatin1Char('0'))); - updateUnreachable1(hlCOctRule); - hlCOctRule = {&rule, nullptr}; + updateUnreachable1(hlCOctRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::HlCStringChar: updateUnreachable1(CharTableArray(detectChars, rule).find(QLatin1Char('\\'))); - updateUnreachable1(hlCStringCharRule); - hlCStringCharRule = {&rule, nullptr}; + updateUnreachable1(hlCStringCharRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::Int: updateUnreachable2(CharTableArray(detectChars, rule).find(QStringLiteral("0123456789"))); - updateUnreachable1(intRule); - intRule = {&rule, nullptr}; + updateUnreachable1(intRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::Float: updateUnreachable2(CharTableArray(detectChars, rule).find(QStringLiteral("0123456789."))); - updateUnreachable1(floatRule); - floatRule = {&rule, nullptr}; + updateUnreachable1(floatRule.setRule(rule)); + break; + + // check if hidden by another DetectIdentifier rule + case Context::Rule::Type::DetectIdentifier: + updateUnreachable1(detectIdentifierRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar or another LineContinue @@ -1865,10 +2037,11 @@ private: case Context::Rule::Type::RangeDetect: updateUnreachable1(CharTableArray(detectChars, rule).find(rule.char0)); if (!isUnreachable) { - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; if (rule2.type == rule.type && isCompatible(rule2) && rule.char0 == rule2.char0 && rule.char1 == rule2.char1) { updateUnreachable1({&rule2, ruleIterator.currentIncludeRules()}); @@ -1884,10 +2057,11 @@ private: } // check that `rule` does not have another RegExpr as a prefix - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; if (rule2.type == Context::Rule::Type::RegExpr && isCompatible(rule2) && rule.insensitive == rule2.insensitive && rule.dynamic == rule2.dynamic && rule.string.startsWith(rule2.string)) { @@ -1902,10 +2076,11 @@ private: case Context::Rule::Type::StringDetect: { // check that dynamic `rule` does not have another dynamic StringDetect as a prefix if (rule.type == Context::Rule::Type::StringDetect && rule.dynamic == XmlBool::True) { - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; if (rule2.type != Context::Rule::Type::StringDetect || rule2.dynamic != XmlBool::True || !isCompatible(rule2)) { @@ -1963,10 +2138,11 @@ private: // combination of uppercase and lowercase RuleAndInclude detect2CharsInsensitives[]{{}, {}, {}, {}}; - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; const bool isSensitive = (rule2.insensitive == XmlBool::True); const auto caseSensitivity = isSensitive ? Qt::CaseInsensitive : Qt::CaseSensitive; @@ -2030,10 +2206,11 @@ private: // check if hidden by another keyword rule case Context::Rule::Type::keyword: { - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; if (rule2.type == Context::Rule::Type::keyword && isCompatible(rule2) && rule.string == rule2.string) { updateUnreachable1({&rule2, ruleIterator.currentIncludeRules()}); @@ -2049,6 +2226,10 @@ private: // <- reference a who will be added // <- hidden by previous rule case Context::Rule::Type::IncludeRules: + if (observedRule.includeRules && !observedRule.hasResolvedIncludeRules()) { + break; + } + if (auto &ruleAndInclude = includeContexts[rule.context.context]) { updateUnreachable1(ruleAndInclude); } @@ -2060,6 +2241,10 @@ private: includeContexts.insert(rulePtr->context.context, RuleAndInclude{rulePtr, &rule}); } + if (observedRule.includeRules) { + break; + } + for (const auto *rulePtr : rule.includedRules) { const auto &rule2 = *rulePtr; switch (rule2.type) { @@ -2087,27 +2272,27 @@ private: } case Context::Rule::Type::HlCChar: - hlCCharRule = {&rule2, &rule}; + hlCCharRule.setRule(rule2, &rule); break; case Context::Rule::Type::HlCHex: - hlCHexRule = {&rule2, &rule}; + hlCHexRule.setRule(rule2, &rule); break; case Context::Rule::Type::HlCOct: - hlCOctRule = {&rule2, &rule}; + hlCOctRule.setRule(rule2, &rule); break; case Context::Rule::Type::HlCStringChar: - hlCStringCharRule = {&rule2, &rule}; + hlCStringCharRule.setRule(rule2, &rule); break; case Context::Rule::Type::Int: - intRule = {&rule2, &rule}; + intRule.setRule(rule2, &rule); break; case Context::Rule::Type::Float: - floatRule = {&rule2, &rule}; + floatRule.setRule(rule2, &rule); break; case Context::Rule::Type::LineContinue: { @@ -2136,12 +2321,18 @@ private: } break; - case Context::Rule::Type::DetectIdentifier: case Context::Rule::Type::Unknown: break; } - if (isUnreachable) { + if (observedRule.includeRules && !observedRule.hasResolvedIncludeRules()) { + auto &unreachableIncludedRule = unreachableIncludedRules[&rule]; + if (isUnreachable && unreachableIncludedRule.alwaysUnreachable) { + unreachableIncludedRule.unreachableBy.append(unreachableBy); + } else { + unreachableIncludedRule.alwaysUnreachable = false; + } + } else if (isUnreachable) { success = false; QString message; message.reserve(128); @@ -2165,7 +2356,7 @@ private: message += QStringLiteral(", "); } message.chop(2); - qWarning() << filename << "line" << rule.line << "unreachable element by" << message; + qWarning() << filename << "line" << rule.line << "unreachable rule by" << message; } } @@ -2179,8 +2370,9 @@ private: { bool success = true; - if (context.rules.isEmpty()) + if (context.rules.isEmpty()) { return success; + } auto it = context.rules.begin(); const auto end = context.rules.end() - 1; @@ -2249,7 +2441,7 @@ private: //! - "#pop!Comment" -> "Comment" //! - "##ISO C++" -> "" //! - "Comment##ISO C++"-> "Comment" in ISO C++ - void resolveContextName(Definition &definition, const Context &context, ContextName &contextName, int line) + void resolveContextName(Definition &definition, Context &context, ContextName &contextName, int line) { QString name = contextName.name; if (name.isEmpty()) { @@ -2281,8 +2473,9 @@ private: const int idx = name.indexOf(QStringLiteral("##")); if (idx == -1) { auto it = definition.contexts.find(name); - if (it != definition.contexts.end()) + if (it != definition.contexts.end()) { contextName.context = &*it; + } } else { auto defName = name.mid(idx + 2); auto listName = name.left(idx); @@ -2392,14 +2585,16 @@ int main(int argc, char *argv[]) QCoreApplication app(argc, argv); // ensure enough arguments are passed - if (app.arguments().size() < 3) + if (app.arguments().size() < 3) { return 1; + } #ifdef QT_XMLPATTERNS_LIB // open schema QXmlSchema schema; - if (!schema.load(QUrl::fromLocalFile(app.arguments().at(2)))) + if (!schema.load(QUrl::fromLocalFile(app.arguments().at(2)))) { return 2; + } #endif const QString hlFilenamesListing = app.arguments().value(3); @@ -2422,7 +2617,7 @@ int main(int argc, char *argv[]) HlFilesChecker filesChecker; QVariantMap hls; int anyError = 0; - for (const QString &hlFilename : qAsConst(hlFilenames)) { + for (const QString &hlFilename : std::as_const(hlFilenames)) { QFile hlFile(hlFilename); if (!hlFile.open(QIODevice::ReadOnly)) { qWarning("Failed to open %s", qPrintable(hlFilename)); @@ -2456,7 +2651,7 @@ int main(int argc, char *argv[]) QVariantMap hl; // transfer text attributes - for (const QString &attribute : qAsConst(textAttributes)) { + for (const QString &attribute : std::as_const(textAttributes)) { hl[attribute] = xml.attributes().value(attribute).toString(); } @@ -2489,17 +2684,20 @@ int main(int argc, char *argv[]) filesChecker.resolveContexts(); - if (!filesChecker.check()) + if (!filesChecker.check()) { anyError = 7; + } // bail out if any problem was seen - if (anyError) + if (anyError) { return anyError; + } // create outfile, after all has worked! QFile outFile(app.arguments().at(1)); - if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) + if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { return 9; + } // write out json outFile.write(QCborValue::fromVariant(QVariant(hls)).toCbor()); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt index 722f92742be..43a60cc19b0 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt @@ -1,6 +1,8 @@ +add_library(KF5SyntaxHighlighting) + ecm_create_qm_loader(syntax_highlighting_QM_LOADER syntaxhighlighting5_qt) -set(syntax_highlighting_srcs +target_sources(KF5SyntaxHighlighting PRIVATE abstracthighlighter.cpp context.cpp contextswitch.cpp @@ -20,8 +22,9 @@ set(syntax_highlighting_srcs themedata.cpp worddelimiters.cpp ${syntax_highlighting_QM_LOADER} + $ ) -ecm_qt_declare_logging_category(syntax_highlighting_srcs +ecm_qt_declare_logging_category(KF5SyntaxHighlighting HEADER ksyntaxhighlighting_logging.h IDENTIFIER KSyntaxHighlighting::Log CATEGORY_NAME kf.syntaxhighlighting @@ -30,16 +33,27 @@ ecm_qt_declare_logging_category(syntax_highlighting_srcs EXPORT KSYNTAXHIGHLIGHTING ) -add_library(KF5SyntaxHighlighting ${syntax_highlighting_srcs} $) -generate_export_header(KF5SyntaxHighlighting BASE_NAME KSyntaxHighlighting) +ecm_generate_export_header(KF5SyntaxHighlighting + BASE_NAME KSyntaxHighlighting + GROUP_BASE_NAME KF + VERSION ${KF_VERSION} + DEPRECATED_BASE_VERSION 0 + DEPRECATION_VERSIONS 5.87 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} +) set_target_properties(KF5SyntaxHighlighting PROPERTIES - VERSION ${SyntaxHighlighting_VERSION_STRING} + VERSION ${SyntaxHighlighting_VERSION} SOVERSION ${SyntaxHighlighting_SOVERSION} EXPORT_NAME SyntaxHighlighting ) target_include_directories(KF5SyntaxHighlighting INTERFACE "$") target_include_directories(KF5SyntaxHighlighting PUBLIC "$") -target_link_libraries(KF5SyntaxHighlighting LINK_PUBLIC Qt5::Gui LINK_PRIVATE Qt5::Network) +target_link_libraries(KF5SyntaxHighlighting + PUBLIC + Qt5::Gui + PRIVATE + Qt5::Network +) ecm_generate_headers(SyntaxHighlighting_HEADERS HEADER_NAMES @@ -52,6 +66,7 @@ ecm_generate_headers(SyntaxHighlighting_HEADERS State SyntaxHighlighter Theme + WildcardMatcher REQUIRED_HEADERS SyntaxHighlighting_HEADERS ) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp index 2ad9d371f90..d6f8cad0c71 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp @@ -36,11 +36,13 @@ void AbstractHighlighterPrivate::ensureDefinitionLoaded() defData = DefinitionData::get(m_definition); } - if (Q_UNLIKELY(!defData->repo && !defData->fileName.isEmpty())) + if (Q_UNLIKELY(!defData->repo && !defData->fileName.isEmpty())) { qCCritical(Log) << "Repository got deleted while a highlighter is still active!"; + } - if (m_definition.isValid()) + if (m_definition.isValid()) { defData->load(); + } } AbstractHighlighter::AbstractHighlighter() @@ -85,7 +87,7 @@ void AbstractHighlighter::setTheme(const Theme &theme) * Returns the index of the first non-space character. If the line is empty, * or only contains white spaces, text.size() is returned. */ -static inline int firstNonSpaceChar(const QString &text) +static inline int firstNonSpaceChar(QStringView text) { for (int i = 0; i < text.length(); ++i) { if (!text[i].isSpace()) { @@ -95,7 +97,14 @@ static inline int firstNonSpaceChar(const QString &text) return text.size(); } +#if KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(5, 87) State AbstractHighlighter::highlightLine(const QString &text, const State &state) +{ + return highlightLine(QStringView(text), state); +} +#endif + +State AbstractHighlighter::highlightLine(QStringView text, const State &state) { Q_D(AbstractHighlighter); @@ -145,8 +154,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state * skipping empty lines after a line continuation character (see bug 405903) */ } else if (!stateData->topContext()->lineEndContext().isStay() - && !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) + && !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { break; + } // guard against endless loops ++endlessLoopingCounter; @@ -160,7 +170,8 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state return newState; } - int offset = 0, beginOffset = 0; + int offset = 0; + int beginOffset = 0; bool lineContinuation = false; /** @@ -247,8 +258,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state skipOffsets.clear(); } const auto currentSkipOffset = skipOffsets.value(rule.get()); - if (currentSkipOffset < 0 || currentSkipOffset > offset) + if (currentSkipOffset < 0 || currentSkipOffset > offset) { continue; + } const auto newResult = rule->doMatch(text, offset, stateData->topCaptures()); newOffset = newResult.offset(); @@ -265,8 +277,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state } } - if (newOffset <= offset) + if (newOffset <= offset) { continue; + } /** * apply folding. @@ -274,12 +287,14 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state * - rule with endRegion + beginRegion: in endRegion, the length is 0 * - rule with lookAhead: length is 0 */ - if (rule->endRegion().isValid() && rule->beginRegion().isValid()) + if (rule->endRegion().isValid() && rule->beginRegion().isValid()) { applyFolding(offset, 0, rule->endRegion()); - else if (rule->endRegion().isValid()) + } else if (rule->endRegion().isValid()) { applyFolding(offset, rule->isLookAhead() ? 0 : newOffset - offset, rule->endRegion()); - if (rule->beginRegion().isValid()) + } + if (rule->beginRegion().isValid()) { applyFolding(offset, rule->isLookAhead() ? 0 : newOffset - offset, rule->beginRegion()); + } if (rule->isLookAhead()) { Q_ASSERT(!rule->context().isStay()); @@ -290,12 +305,14 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state d->switchContext(stateData, rule->context(), newResult.captures()); newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat(); - if (newOffset == text.size() && std::dynamic_pointer_cast(rule)) + if (newOffset == text.size() && std::dynamic_pointer_cast(rule)) { lineContinuation = true; + } break; } - if (isLookAhead) + if (isLookAhead) { continue; + } if (newOffset <= offset) { // no matching rule if (stateData->topContext()->fallthrough()) { @@ -316,8 +333,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state * on format change, apply the last one and switch to new one */ if (newFormat != currentFormat && newFormat->id() != currentFormat->id()) { - if (offset > 0) + if (offset > 0) { applyFormat(beginOffset, offset - beginOffset, *currentFormat); + } beginOffset = offset; currentFormat = newFormat; } @@ -333,8 +351,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state /** * apply format for remaining text, if any */ - if (beginOffset < offset) + if (beginOffset < offset) { applyFormat(beginOffset, text.size() - beginOffset, *currentFormat); + } /** * handle line end context switches @@ -344,8 +363,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state { int endlessLoopingCounter = 0; while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) { - if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) + if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { break; + } // guard against endless loops ++endlessLoopingCounter; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h index 5e85873ce03..49cfbf25303 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h @@ -108,6 +108,15 @@ protected: AbstractHighlighter(); AbstractHighlighter(AbstractHighlighterPrivate *dd); +#if KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(5, 87) + /** + * @copydoc highlightLine(QStringView,const State&) + * @deprecated since 5.87, use highlightLine(QStringView, const State&) instead. + */ + // no deprecation warning, as removal of this will automatically "port" the using code + State highlightLine(const QString &text, const State &state); +#endif + // TODO KF6: add an optional void* context argument that is passed through // to the applyX() calls, so highlighters dealing with some form of line object // (such as QSyntaxHighlighter or KTextEditor) can avoid some ugly hacks to have @@ -120,14 +129,14 @@ protected: * @param state The highlighting state handle returned by the call * to highlightLine() for the previous line. For the very first line, * just pass a default constructed State(). - * @returns The state of the highlighing engine after processing the + * @returns The state of the highlighting engine after processing the * given line. This needs to passed into highlightLine() for the * next line. You can store the state for efficient partial * re-highlighting for example during editing. * * @see applyFormat(), applyFolding() */ - State highlightLine(const QString &text, const State &state); + State highlightLine(QStringView text, const State &state); /** * Reimplement this to apply formats to your output. The provided @p format diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp index 9ff012e1d72..8ae47d80ebf 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp @@ -33,10 +33,6 @@ struct CieLab { double b; }; -#ifndef M_PI -constexpr double M_PI = 3.14159265358979323846; -#endif - // clang-format off // xterm color reference // constexpr Rgb888 xterm256Colors[] { @@ -388,10 +384,11 @@ CieLab rgbToLab(QRgb rgb) // Perform the inverse gamma companding for a sRGB color // http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html auto inverseGammaCompanding = [](int c) { - if (c <= 10) + if (c <= 10) { return c / (255.0 * 12.92); - else + } else { return std::pow((c / 255.0 + 0.055) / 1.055, 2.4); + } }; const double r = inverseGammaCompanding(qRed(rgb)); @@ -404,10 +401,11 @@ CieLab rgbToLab(QRgb rgb) // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html auto f = [](double t) { - if (t > 216.0 / 24389.0) + if (t > 216.0 / 24389.0) { return std::cbrt(t); - else + } else { return t * (24389.0 / (27.0 * 116.0)) + 4.0 / 29.0; + } }; const double f_x = f(x / illuminant_D65[0]); @@ -440,8 +438,9 @@ inline double pow2(double x) inline double computeHPrime(double a_prime, double b) { - if (std::abs(a_prime) < epsilon && std::abs(b) < epsilon) + if (std::abs(a_prime) < epsilon && std::abs(b) < epsilon) { return 0.0; + } const double value = std::atan2(b, a_prime) * 180.0 / M_PI; return (value < 0.0) ? value + 360.0 : value; @@ -449,34 +448,38 @@ inline double computeHPrime(double a_prime, double b) inline double computeDeltaHPrime(double C1_prime, double C2_prime, double h1_prime, double h2_prime) { - if (C1_prime * C2_prime < epsilon) + if (C1_prime * C2_prime < epsilon) { return 0.0; + } const double diff = h2_prime - h1_prime; - if (std::abs(diff) <= 180.0) + if (std::abs(diff) <= 180.0) { return diff; - else if (diff > 180.0) + } else if (diff > 180.0) { return diff - 360.0; - else + } else { return diff + 360.0; + } } inline double computeHPrimeBar(double C1_prime, double C2_prime, double h1_prime, double h2_prime) { const double sum = h1_prime + h2_prime; - if (C1_prime * C2_prime < epsilon) + if (C1_prime * C2_prime < epsilon) { return sum; + } const double dist = std::abs(h1_prime - h2_prime); - if (dist <= 180.0) + if (dist <= 180.0) { return 0.5 * sum; - else if (sum < 360.0) + } else if (sum < 360.0) { return 0.5 * (sum + 360.0); - else + } else { return 0.5 * (sum - 360.0); + } } /// Calculate the perceptual color difference based on CIEDE2000. @@ -702,7 +705,7 @@ struct GraphLine { const int n2 = offset - labelLineLength; labelLineLength += n2 + 1; fillLine(labelLine, n2); - labelLine += graphLine.rightRef(graphLine.size() - ps1); + labelLine += QStringView(graphLine).right(graphLine.size() - ps1); } } @@ -781,8 +784,9 @@ public: state = highlightLine(currentLine, state); if (hasSeparator) { - if (!firstLine) + if (!firstLine) { out << QStringLiteral("\x1b[0m────────────────────────────────────────────────────\x1b[K\n"); + } firstLine = false; } @@ -793,14 +797,15 @@ public: for (const auto &fragment : m_highlightedFragments) { auto const &ansiStyle = ansiStyles[fragment.formatId]; - out << ansiStyle.first << currentLine.midRef(fragment.offset, fragment.length) << ansiStyle.second; + out << ansiStyle.first << QStringView(currentLine).mid(fragment.offset, fragment.length) << ansiStyle.second; } out << QStringLiteral("\x1b[K\n"); if (hasFormatOrContextTrace && !m_highlightedFragments.empty()) { - if (m_hasContextTrace || m_hasStackSizeTrace) + if (m_hasContextTrace || m_hasStackSizeTrace) { appendContextNames(oldState, currentLine); + } printFormats(out, infoStyle, ansiStyles); out << resetBgColor; @@ -817,8 +822,9 @@ public: void applyFolding(int offset, int /*length*/, FoldingRegion region) override { - if (!m_hasRegionTrace) + if (!m_hasRegionTrace) { return; + } const auto id = region.id(); @@ -829,8 +835,9 @@ public: auto &previousRegion = m_regions[m_regions.size() - 2]; if (previousRegion.state == Region::State::Close && previousRegion.offset == offset) { std::swap(previousRegion, m_regions.back()); - if (previousRegion.bindIndex != -1) + if (previousRegion.bindIndex != -1) { m_regions[previousRegion.bindIndex].bindIndex = m_regions.size() - 1; + } } } ++m_regionDepth; @@ -840,10 +847,11 @@ public: auto eit = m_regions.rend(); for (int depth = 0; it != eit; ++it) { if (it->regionId == id && it->bindIndex < 0) { - if (it->state == Region::State::Close) + if (it->state == Region::State::Close) { ++depth; - else if (--depth < 0) + } else if (--depth < 0) { break; + } } } @@ -868,8 +876,9 @@ private: void initRegionStyles(const std::vector> &ansiStyles) { m_regionStyles.resize(ansiStyles.size()); - for (std::size_t i = 0; i < m_regionStyles.size(); ++i) + for (std::size_t i = 0; i < m_regionStyles.size(); ++i) { m_regionStyles[i] = ansiStyles[i].first; + } std::sort(m_regionStyles.begin(), m_regionStyles.end()); m_regionStyles.erase(std::unique(m_regionStyles.begin(), m_regionStyles.end()), m_regionStyles.end()); @@ -1216,7 +1225,7 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE } // initialize ansiStyles - for (auto &&definition : qAsConst(definitions)) { + for (auto &&definition : std::as_const(definitions)) { const auto formats = definition.formats(); for (auto &&format : formats) { const auto id = format.id(); @@ -1236,20 +1245,26 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE const bool hasUnderline = format.isUnderline(theme); const bool hasStrikeThrough = format.isStrikeThrough(theme); - if (hasFg) + if (hasFg) { buffer.appendForeground(format.textColor(theme).rgb(), is256Colors, colorCache); - else + } else { buffer.append(foregroundDefaultColor); - if (hasBg) + } + if (hasBg) { buffer.appendBackground(format.backgroundColor(theme).rgb(), is256Colors, colorCache); - if (hasBold) + } + if (hasBold) { buffer.append(QLatin1String("1;")); - if (hasItalic) + } + if (hasItalic) { buffer.append(QLatin1String("3;")); - if (hasUnderline) + } + if (hasUnderline) { buffer.append(QLatin1String("4;")); - if (hasStrikeThrough) + } + if (hasStrikeThrough) { buffer.append(QLatin1String("9;")); + } // if there is ANSI style if (buffer.latin1().size() > 2) { @@ -1266,14 +1281,18 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE d->ansiStyles[id].second = buffer.latin1(); } else if (hasEffect) { buffer.append(QLatin1String("\x1b[")); - if (hasBold) + if (hasBold) { buffer.append(QLatin1String("21;")); - if (hasItalic) + } + if (hasItalic) { buffer.append(QLatin1String("23;")); - if (hasUnderline) + } + if (hasUnderline) { buffer.append(QLatin1String("24;")); - if (hasStrikeThrough) + } + if (hasStrikeThrough) { buffer.append(QLatin1String("29;")); + } buffer.setFinalStyle(); d->ansiStyles[id].second = buffer.latin1(); } @@ -1301,10 +1320,11 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE d->currentLine = in.readLine(); state = highlightLine(d->currentLine, state); - if (useEditorBackground) + if (useEditorBackground) { d->out << QStringLiteral("\x1b[K\n"); - else + } else { d->out << QLatin1Char('\n'); + } } } else { AnsiBuffer buffer; @@ -1328,5 +1348,5 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE void AnsiHighlighter::applyFormat(int offset, int length, const Format &format) { auto const &ansiStyle = d->ansiStyles[format.id()]; - d->out << ansiStyle.first << d->currentLine.midRef(offset, length) << ansiStyle.second; + d->out << ansiStyle.first << QStringView(d->currentLine).mid(offset, length) << ansiStyle.second; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp index f980ea5be80..724f37a03f1 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp @@ -30,8 +30,9 @@ void Context::setDefinition(const DefinitionRef &def) bool Context::indentationBasedFoldingEnabled() const { - if (m_noIndentationBasedFolding) + if (m_noIndentationBasedFolding) { return false; + } return m_def.definition().indentationBasedFoldingEnabled(); } @@ -56,8 +57,9 @@ void Context::load(QXmlStreamReader &reader) auto rule = Rule::create(reader.name()); if (rule) { rule->setDefinition(m_def.definition()); - if (rule->load(reader)) + if (rule->load(reader)) { m_rules.push_back(std::move(rule)); + } } else { reader.skipCurrentElement(); } @@ -79,8 +81,9 @@ void Context::resolveContexts() m_lineEndContext.resolve(def); m_lineEmptyContext.resolve(def); m_fallthroughContext.resolve(def); - for (const auto &rule : m_rules) + for (const auto &rule : m_rules) { rule->resolveContext(); + } } Context::ResolveState Context::resolveState() @@ -100,8 +103,9 @@ Context::ResolveState Context::resolveState() void Context::resolveIncludes() { - if (resolveState() == Resolved) + if (resolveState() == Resolved) { return; + } if (resolveState() == Resolving) { qCWarning(Log) << "Cyclic dependency!"; return; @@ -129,10 +133,11 @@ void Context::resolveIncludes() } auto defData = DefinitionData::get(def); defData->load(); - if (inc->contextName().isEmpty()) + if (inc->contextName().isEmpty()) { context = defData->initialContext(); - else + } else { context = defData->contextByName(inc->contextName()); + } } if (!context) { qCWarning(Log) << "Unable to resolve include rule for definition" << inc->contextName() << "##" << inc->definitionName() << "in" diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp index 7ccd73ee9b7..e829af463a3 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp @@ -29,8 +29,9 @@ Context *ContextSwitch::context() const void ContextSwitch::parse(QStringView contextInstr) { - if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay")) + if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay")) { return; + } if (contextInstr.startsWith(QLatin1String("#pop!"))) { ++m_popCount; @@ -60,13 +61,15 @@ void ContextSwitch::resolve(const Definition &def) d = DefinitionData::get(def)->repo->definitionForName(m_defName); auto data = DefinitionData::get(d); data->load(); - if (m_contextName.isEmpty()) + if (m_contextName.isEmpty()) { m_context = data->initialContext(); + } } if (!m_contextName.isEmpty()) { m_context = DefinitionData::get(d)->contextByName(m_contextName); - if (!m_context) + if (!m_context) { qCWarning(Log) << "cannot find context" << m_contextName << "in" << def.name(); + } } } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp index 7434e745b23..068907a4e28 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp @@ -51,30 +51,21 @@ DefinitionData *DefinitionData::get(const Definition &def) Definition::Definition() : d(new DefinitionData) -{ -} - -Definition::Definition(const Definition &other) - : d(other.d) { d->q = *this; } +Definition::Definition(Definition &&other) noexcept = default; +Definition::Definition(const Definition &) = default; +Definition::~Definition() = default; +Definition &Definition::operator=(Definition &&other) noexcept = default; +Definition &Definition::operator=(const Definition &) = default; + Definition::Definition(std::shared_ptr &&dd) : d(std::move(dd)) { } -Definition::~Definition() -{ -} - -Definition &Definition::operator=(const Definition &rhs) -{ - d = rhs.d; - return *this; -} - bool Definition::operator==(const Definition &other) const { return d->fileName == other.d->fileName; @@ -223,8 +214,9 @@ bool Definition::setKeywordList(const QString &name, const QStringList &content) if (list) { list->setKeywordList(content); return true; - } else + } else { return false; + } } QVector Definition::formats() const @@ -251,7 +243,7 @@ QVector Definition::includedDefinitions() const // Iterate all context rules to find associated Definitions. This will // automatically catch other Definitions referenced with IncludeRuldes or ContextSwitch. const auto definition = queue.takeLast(); - for (const auto &context : qAsConst(definition.d->contexts)) { + for (const auto &context : std::as_const(definition.d->contexts)) { // handle context switch attributes of this context itself for (const auto switchContext : {context->lineEndContext().context(), context->lineEmptyContext().context(), context->fallthroughContext().context()}) { @@ -321,8 +313,9 @@ Context *DefinitionData::initialContext() const Context *DefinitionData::contextByName(const QString &wantedName) const { for (const auto context : contexts) { - if (context->name() == wantedName) + if (context->name() == wantedName) { return context; + } } return nullptr; } @@ -336,8 +329,9 @@ KeywordList *DefinitionData::keywordList(const QString &wantedName) Format DefinitionData::formatByName(const QString &wantedName) const { const auto it = formats.constFind(wantedName); - if (it != formats.constEnd()) + if (it != formats.constEnd()) { return it.value(); + } return Format(); } @@ -349,24 +343,29 @@ bool DefinitionData::isLoaded() const bool DefinitionData::load(OnlyKeywords onlyKeywords) { - if (fileName.isEmpty()) + if (fileName.isEmpty()) { return false; + } - if (isLoaded()) + if (isLoaded()) { return true; + } - if (bool(onlyKeywords) && keywordIsLoaded) + if (bool(onlyKeywords) && keywordIsLoaded) { return true; + } QFile file(fileName); - if (!file.open(QFile::ReadOnly)) + if (!file.open(QFile::ReadOnly)) { return false; + } QXmlStreamReader reader(&file); while (!reader.atEnd()) { const auto token = reader.readNext(); - if (token != QXmlStreamReader::StartElement) + if (token != QXmlStreamReader::StartElement) { continue; + } if (reader.name() == QLatin1String("highlighting")) { loadHighlighting(reader, onlyKeywords); @@ -375,21 +374,22 @@ bool DefinitionData::load(OnlyKeywords onlyKeywords) } } - else if (reader.name() == QLatin1String("general")) + else if (reader.name() == QLatin1String("general")) { loadGeneral(reader); + } } for (auto it = keywordLists.begin(); it != keywordLists.end(); ++it) { it->setCaseSensitivity(caseSensitive); } - for (const auto context : qAsConst(contexts)) { + for (const auto context : std::as_const(contexts)) { context->resolveContexts(); context->resolveIncludes(); context->resolveAttributeFormat(); } - for (const auto context : qAsConst(contexts)) { + for (const auto context : std::as_const(contexts)) { for (const auto &rule : context->rules()) { rule->resolvePostProcessing(); } @@ -427,14 +427,16 @@ bool DefinitionData::loadMetaData(const QString &definitionFileName) fileName = definitionFileName; QFile file(definitionFileName); - if (!file.open(QFile::ReadOnly)) + if (!file.open(QFile::ReadOnly)) { return false; + } QXmlStreamReader reader(&file); while (!reader.atEnd()) { const auto token = reader.readNext(); - if (token != QXmlStreamReader::StartElement) + if (token != QXmlStreamReader::StartElement) { continue; + } if (reader.name() == QLatin1String("language")) { return loadLanguage(reader); } @@ -457,11 +459,13 @@ bool DefinitionData::loadMetaData(const QString &file, const QCborMap &obj) fileName = file; const auto exts = obj.value(QLatin1String("extensions")).toString(); - for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) + for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { extensions.push_back(ext); + } const auto mts = obj.value(QLatin1String("mimetype")).toString(); - for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) + for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { mimetypes.push_back(mt); + } return true; } @@ -471,8 +475,9 @@ bool DefinitionData::loadLanguage(QXmlStreamReader &reader) Q_ASSERT(reader.name() == QLatin1String("language")); Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); - if (!checkKateVersion(reader.attributes().value(QLatin1String("kateversion")))) + if (!checkKateVersion(reader.attributes().value(QLatin1String("kateversion")))) { return false; + } name = reader.attributes().value(QLatin1String("name")).toString(); section = reader.attributes().value(QLatin1String("section")).toString(); @@ -485,13 +490,16 @@ bool DefinitionData::loadLanguage(QXmlStreamReader &reader) author = reader.attributes().value(QLatin1String("author")).toString(); license = reader.attributes().value(QLatin1String("license")).toString(); const auto exts = reader.attributes().value(QLatin1String("extensions")).toString(); - for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) + for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { extensions.push_back(ext); + } const auto mts = reader.attributes().value(QLatin1String("mimetype")).toString(); - for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) + for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { mimetypes.push_back(mt); - if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) + } + if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) { caseSensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive; + } return true; } @@ -618,8 +626,9 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader) ++elementRefCounter; if (reader.name() == QLatin1String("keywords")) { - if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) + if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) { caseSensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive; + } // adapt wordDelimiters wordDelimiters.append(reader.attributes().value(QLatin1String("additionalDeliminator"))); @@ -628,14 +637,15 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader) // adapt WordWrapDelimiters auto wordWrapDeliminatorAttr = reader.attributes().value( QLatin1String("wordWrapDeliminator")); - if (wordWrapDeliminatorAttr.isEmpty()) + if (wordWrapDeliminatorAttr.isEmpty()) { wordWrapDelimiters = wordDelimiters; - else { + } else { wordWrapDelimiters.append(wordWrapDeliminatorAttr); } } else if (reader.name() == QLatin1String("folding")) { - if (reader.attributes().hasAttribute(QLatin1String("indentationsensitive"))) + if (reader.attributes().hasAttribute(QLatin1String("indentationsensitive"))) { indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("indentationsensitive"))); + } } else if (reader.name() == QLatin1String("emptyLines")) { loadFoldingIgnoreList(reader); } else if (reader.name() == QLatin1String("comments")) { @@ -649,8 +659,9 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader) break; case QXmlStreamReader::EndElement: --elementRefCounter; - if (elementRefCounter == 0) + if (elementRefCounter == 0) { return; + } reader.readNext(); break; default: @@ -688,8 +699,9 @@ void DefinitionData::loadComments(QXmlStreamReader &reader) break; case QXmlStreamReader::EndElement: --elementRefCounter; - if (elementRefCounter == 0) + if (elementRefCounter == 0) { return; + } reader.readNext(); break; default: @@ -719,8 +731,9 @@ void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader &reader) break; case QXmlStreamReader::EndElement: --elementRefCounter; - if (elementRefCounter == 0) + if (elementRefCounter == 0) { return; + } reader.readNext(); break; default: @@ -754,8 +767,9 @@ void DefinitionData::loadSpellchecking(QXmlStreamReader &reader) break; case QXmlStreamReader::EndElement: --elementRefCounter; - if (elementRefCounter == 0) + if (elementRefCounter == 0) { return; + } reader.readNext(); break; default: @@ -798,10 +812,6 @@ DefinitionRef::DefinitionRef(const Definition &def) { } -DefinitionRef::~DefinitionRef() -{ -} - DefinitionRef &DefinitionRef::operator=(const Definition &def) { d = def.d; @@ -810,8 +820,9 @@ DefinitionRef &DefinitionRef::operator=(const Definition &def) Definition DefinitionRef::definition() const { - if (!d.expired()) + if (!d.expired()) { return Definition(d.lock()); + } return Definition(); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h index 8226fbdd24f..05757ea52a3 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h @@ -13,6 +13,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE class QChar; @@ -74,7 +75,7 @@ enum class CommentPosition { * singleLineCommentMarker() and multiLineCommentMarker() provide comment * markers that can be used for commenting/uncommenting code. Similarly, * formats() returns a list of Format items defined by this Definition (which - * equal the itemDatas of a highlighing definition file). includedDefinitions() + * equal the itemDatas of a highlighting definition file). includedDefinitions() * returns a list of all included Definition%s referenced by this Definition via * the rule IncludeRules, which is useful for displaying all Format items for * color configuration in the user interface. @@ -84,6 +85,13 @@ enum class CommentPosition { */ class KSYNTAXHIGHLIGHTING_EXPORT Definition { + Q_GADGET + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString translatedName READ translatedName) + Q_PROPERTY(QString section READ section) + Q_PROPERTY(QString translatedSection READ translatedSection) + Q_PROPERTY(QString author READ author) + Q_PROPERTY(QString license READ license) public: /** * Default constructor, creating an empty (invalid) Definition instance. @@ -93,6 +101,14 @@ public: */ Definition(); + /** + * Move constructor. + * This definition takes the Definition data from @p other. + * @note @p other may only be assigned to or destroyed afterwards. + * @since 5.86 + */ + Definition(Definition &&other) noexcept; + /** * Copy constructor. * Both this definition as well as @p other share the Definition data. @@ -105,7 +121,15 @@ public: ~Definition(); /** - * Assignment operator. + * Move assignment operator. + * This definition takes the Definition data from @p other. + * @note @p other may only be assigned to or destroyed afterwards. + * @since 5.86 + */ + Definition &operator=(Definition &&other) noexcept; + + /** + * Copy assignment operator. * Both this definition as well as @p rhs share the Definition data. */ Definition &operator=(const Definition &rhs); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp index 3dff1dd4366..b16139b731f 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp @@ -51,24 +51,27 @@ void DefinitionDownloaderPrivate::definitionListDownloadFinished(QNetworkReply * while (!parser.atEnd()) { switch (parser.readNext()) { case QXmlStreamReader::StartElement: - if (parser.name() == QLatin1String("Definition")) + if (parser.name() == QLatin1String("Definition")) { updateDefinition(parser); + } break; default: break; } } - if (pendingDownloads == 0) + if (pendingDownloads == 0) { Q_EMIT q->informationMessage(QObject::tr("All syntax definitions are up-to-date.")); + } checkDone(); } void DefinitionDownloaderPrivate::updateDefinition(QXmlStreamReader &parser) { const auto name = parser.attributes().value(QLatin1String("name")); - if (name.isEmpty()) + if (name.isEmpty()) { return; + } auto localDef = repo->definitionForName(name.toString()); if (!localDef.isValid()) { @@ -86,11 +89,13 @@ void DefinitionDownloaderPrivate::updateDefinition(QXmlStreamReader &parser) void DefinitionDownloaderPrivate::downloadDefinition(const QUrl &downloadUrl) { - if (!downloadUrl.isValid()) + if (!downloadUrl.isValid()) { return; + } auto url = downloadUrl; - if (url.scheme() == QLatin1String("http")) + if (url.scheme() == QLatin1String("http")) { url.setScheme(QStringLiteral("https")); + } QNetworkRequest req(url); auto reply = nam->get(req); @@ -133,8 +138,9 @@ void DefinitionDownloaderPrivate::downloadDefinitionFinished(QNetworkReply *repl void DefinitionDownloaderPrivate::checkDone() { if (pendingDownloads == 0) { - if (needsReload) + if (needsReload) { repo->reload(); + } Q_EMIT QTimer::singleShot(0, q, &DefinitionDownloader::done); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h index 25a1a749e49..285fec3e206 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h @@ -13,7 +13,6 @@ namespace KSyntaxHighlighting { class Definition; class DefinitionData; -class DefinitionPrivate; /** Weak reference for Definition instances. * @@ -21,6 +20,8 @@ class DefinitionPrivate; * in objects hold directly or indirectly by Definition * to avoid reference count loops and thus memory leaks. * + * This class follows the rule of zero. It is implicitly movable and copyable. + * * @internal */ class DefinitionRef @@ -28,7 +29,6 @@ class DefinitionRef public: DefinitionRef(); explicit DefinitionRef(const Definition &def); - ~DefinitionRef(); DefinitionRef &operator=(const Definition &def); Definition definition() const; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp index d459ee36d88..bcc64c3c2bc 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp @@ -21,8 +21,9 @@ using namespace KSyntaxHighlighting; static Theme::TextStyle stringToDefaultFormat(QStringView str) { - if (!str.startsWith(QLatin1String("ds"))) + if (!str.startsWith(QLatin1String("ds"))) { return Theme::Normal; + } static const auto idx = Theme::staticMetaObject.indexOfEnumerator("TextStyle"); Q_ASSERT(idx >= 0); @@ -30,8 +31,9 @@ static Theme::TextStyle stringToDefaultFormat(QStringView str) bool ok = false; const auto value = metaEnum.keyToValue(str.mid(2).toLatin1().constData(), &ok); - if (!ok || value < 0) + if (!ok || value < 0) { return Theme::Normal; + } return static_cast(value); } @@ -44,8 +46,9 @@ FormatPrivate *FormatPrivate::detachAndGet(Format &format) TextStyleData FormatPrivate::styleOverride(const Theme &theme) const { const auto themeData = ThemeData::get(theme); - if (themeData) + if (themeData) { return themeData->textStyleOverride(definition.definition().name(), name); + } return TextStyleData(); } @@ -113,16 +116,18 @@ bool Format::hasTextColor(const Theme &theme) const QColor Format::textColor(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.textColor) + if (overrideStyle.textColor) { return overrideStyle.textColor; + } return d->style.textColor ? QColor::fromRgba(d->style.textColor) : QColor::fromRgba(theme.textColor(d->defaultStyle)); } QColor Format::selectedTextColor(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.selectedTextColor) + if (overrideStyle.selectedTextColor) { return overrideStyle.selectedTextColor; + } return d->style.selectedTextColor ? QColor::fromRgba(d->style.selectedTextColor) : QColor::fromRgba(theme.selectedTextColor(d->defaultStyle)); } @@ -136,8 +141,9 @@ bool Format::hasBackgroundColor(const Theme &theme) const QColor Format::backgroundColor(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.backgroundColor) + if (overrideStyle.backgroundColor) { return overrideStyle.backgroundColor; + } // use QColor::fromRgba for background QRgb => QColor conversion to avoid unset colors == black! return d->style.backgroundColor ? QColor::fromRgba(d->style.backgroundColor) : QColor::fromRgba(theme.backgroundColor(d->defaultStyle)); @@ -146,8 +152,9 @@ QColor Format::backgroundColor(const Theme &theme) const QColor Format::selectedBackgroundColor(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.selectedBackgroundColor) + if (overrideStyle.selectedBackgroundColor) { return overrideStyle.selectedBackgroundColor; + } // use QColor::fromRgba for background QRgb => QColor conversion to avoid unset colors == black! return d->style.selectedBackgroundColor ? QColor::fromRgba(d->style.selectedBackgroundColor) @@ -157,32 +164,36 @@ QColor Format::selectedBackgroundColor(const Theme &theme) const bool Format::isBold(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.hasBold) + if (overrideStyle.hasBold) { return overrideStyle.bold; + } return d->style.hasBold ? d->style.bold : theme.isBold(d->defaultStyle); } bool Format::isItalic(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.hasItalic) + if (overrideStyle.hasItalic) { return overrideStyle.italic; + } return d->style.hasItalic ? d->style.italic : theme.isItalic(d->defaultStyle); } bool Format::isUnderline(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.hasUnderline) + if (overrideStyle.hasUnderline) { return overrideStyle.underline; + } return d->style.hasUnderline ? d->style.underline : theme.isUnderline(d->defaultStyle); } bool Format::isStrikeThrough(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.hasStrikeThrough) + if (overrideStyle.hasStrikeThrough) { return overrideStyle.strikeThrough; + } return d->style.hasStrikeThrough ? d->style.strikeThrough : theme.isStrikeThrough(d->defaultStyle); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp index 5ba421d0e1b..688a42d45cd 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp @@ -70,10 +70,11 @@ void HtmlHighlighter::highlightFile(const QString &fileName, const QString &titl return; } - if (title.isEmpty()) + if (title.isEmpty()) { highlightData(&f, fi.fileName()); - else + } else { highlightData(&f, title); + } } /** @@ -87,8 +88,9 @@ void HtmlHighlighter::highlightFile(const QString &fileName, const QString &titl */ static QString toHtmlRgbaString(const QColor &color) { - if (color.alpha() == 0xFF) + if (color.alpha() == 0xFF) { return color.name(); + } QString rgba = QStringLiteral("rgba("); rgba.append(QString::number(color.red())); @@ -111,10 +113,11 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) } QString htmlTitle; - if (title.isEmpty()) + if (title.isEmpty()) { htmlTitle = QStringLiteral("Kate Syntax Highlighter"); - else + } else { htmlTitle = title.toHtmlEscaped(); + } State state; *d->out << "\n"; @@ -125,8 +128,9 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) << ")\"/>\n"; *d->out << "out << " style=\"background-color:" << toHtmlRgbaString(QColor::fromRgba(theme().editorColor(Theme::BackgroundColor))); - if (theme().textColor(Theme::Normal)) + if (theme().textColor(Theme::Normal)) { *d->out << ";color:" << toHtmlRgbaString(QColor::fromRgba(theme().textColor(Theme::Normal))); + } *d->out << "\">

\n";
 
     QTextStream in(dev);
@@ -148,27 +152,34 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title)
 
 void HtmlHighlighter::applyFormat(int offset, int length, const Format &format)
 {
-    if (length == 0)
+    if (length == 0) {
         return;
+    }
 
     // collect potential output, cheaper than thinking about "is there any?"
     QVarLengthArray formatOutput;
-    if (format.hasTextColor(theme()))
+    if (format.hasTextColor(theme())) {
         formatOutput << QStringLiteral("color:") << toHtmlRgbaString(format.textColor(theme())) << QStringLiteral(";");
-    if (format.hasBackgroundColor(theme()))
+    }
+    if (format.hasBackgroundColor(theme())) {
         formatOutput << QStringLiteral("background-color:") << toHtmlRgbaString(format.backgroundColor(theme())) << QStringLiteral(";");
-    if (format.isBold(theme()))
+    }
+    if (format.isBold(theme())) {
         formatOutput << QStringLiteral("font-weight:bold;");
-    if (format.isItalic(theme()))
+    }
+    if (format.isItalic(theme())) {
         formatOutput << QStringLiteral("font-style:italic;");
-    if (format.isUnderline(theme()))
+    }
+    if (format.isUnderline(theme())) {
         formatOutput << QStringLiteral("text-decoration:underline;");
-    if (format.isStrikeThrough(theme()))
+    }
+    if (format.isStrikeThrough(theme())) {
         formatOutput << QStringLiteral("text-decoration:line-through;");
+    }
 
     if (!formatOutput.isEmpty()) {
         *d->out << "out << out;
         }
         *d->out << "\">";
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
index b13e30607ba..3a7514897a3 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
@@ -16,6 +16,27 @@
 
 using namespace KSyntaxHighlighting;
 
+namespace
+{
+struct KeywordComparator {
+    Qt::CaseSensitivity caseSensitive;
+
+    bool operator()(QStringView a, QStringView b) const
+    {
+        if (a.size() < b.size()) {
+            return true;
+        }
+
+        if (a.size() > b.size()) {
+            return false;
+        }
+
+        return a.compare(b, caseSensitive) < 0;
+    }
+};
+
+}
+
 bool KeywordList::contains(QStringView str, Qt::CaseSensitivity caseSensitive) const
 {
     /**
@@ -26,9 +47,7 @@ bool KeywordList::contains(QStringView str, Qt::CaseSensitivity caseSensitive) c
     /**
      * search with right predicate
      */
-    return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), QStringView(str), [caseSensitive](QStringView a, QStringView b) {
-        return a.compare(b, caseSensitive) < 0;
-    });
+    return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), QStringView(str), KeywordComparator{caseSensitive});
 }
 
 void KeywordList::load(QXmlStreamReader &reader)
@@ -85,16 +104,14 @@ void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive
      * fill vector with refs to keywords
      */
     vectorToSort.reserve(m_keywords.size());
-    for (const auto &keyword : qAsConst(m_keywords)) {
+    for (const auto &keyword : std::as_const(m_keywords)) {
         vectorToSort.push_back(keyword);
     }
 
     /**
      * sort with right predicate
      */
-    std::sort(vectorToSort.begin(), vectorToSort.end(), [caseSensitive](QStringView a, QStringView b) {
-        return a.compare(b, caseSensitive) < 0;
-    });
+    std::sort(vectorToSort.begin(), vectorToSort.end(), KeywordComparator{caseSensitive});
 }
 
 void KeywordList::resolveIncludeKeywords(DefinitionData &def)
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h b/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h
deleted file mode 100644
index a39adb5ed6f..00000000000
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 
-
-#if defined(KSYNTAXHIGHLIGHTING_LIBRARY)
-#  define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_EXPORT
-#else
-#  define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_IMPORT
-#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
index 1e3191a7bce..f3b36df4593 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
@@ -11,7 +11,7 @@
 #include "repository_p.h"
 #include "theme.h"
 #include "themedata_p.h"
-#include "wildcardmatcher_p.h"
+#include "wildcardmatcher.h"
 
 #include 
 #include 
@@ -19,15 +19,75 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #ifndef NO_STANDARD_PATHS
 #include 
 #endif
 
+#include 
+#include 
 #include 
 
 using namespace KSyntaxHighlighting;
 
+namespace
+{
+QString fileNameFromFilePath(const QString &filePath)
+{
+    return QFileInfo{filePath}.fileName();
+}
+
+auto anyWildcardMatches(QStringView str)
+{
+    return [str](const Definition &def) {
+        const auto strings = def.extensions();
+        return std::any_of(strings.cbegin(), strings.cend(), [str](QStringView wildcard) {
+            return WildcardMatcher::exactMatch(str, wildcard);
+        });
+    };
+}
+
+auto anyMimeTypeEquals(QStringView mimeTypeName)
+{
+    return [mimeTypeName](const Definition &def) {
+        const auto strings = def.mimeTypes();
+        return std::any_of(strings.cbegin(), strings.cend(), [mimeTypeName](QStringView name) {
+            return mimeTypeName == name;
+        });
+    };
+}
+
+// The two function templates below take defs - a map sorted by highlighting name - to be deterministic and independent of translations.
+
+template
+Definition findHighestPriorityDefinitionIf(const QMap &defs, UnaryPredicate predicate)
+{
+    const Definition *match = nullptr;
+    auto matchPriority = std::numeric_limits::lowest();
+    for (const Definition &def : defs) {
+        const auto defPriority = def.priority();
+        if (defPriority > matchPriority && predicate(def)) {
+            match = &def;
+            matchPriority = defPriority;
+        }
+    }
+    return match == nullptr ? Definition{} : *match;
+}
+
+template
+QVector findDefinitionsIf(const QMap &defs, UnaryPredicate predicate)
+{
+    QVector matches;
+    std::copy_if(defs.cbegin(), defs.cend(), std::back_inserter(matches), predicate);
+    std::stable_sort(matches.begin(), matches.end(), [](const Definition &lhs, const Definition &rhs) {
+        return lhs.priority() > rhs.priority();
+    });
+    return matches;
+}
+} // unnamed namespace
+
 static void initResource()
 {
 #ifdef HAS_SYNTAX_RESOURCE
@@ -52,8 +112,9 @@ Repository::~Repository()
 {
     // reset repo so we can detect in still alive definition instances
     // that the repo was deleted
-    for (const auto &def : qAsConst(d->m_sortedDefs))
+    for (const auto &def : std::as_const(d->m_sortedDefs)) {
         DefinitionData::get(def)->repo = nullptr;
+    }
 }
 
 Definition Repository::definitionForName(const QString &defName) const
@@ -61,58 +122,24 @@ Definition Repository::definitionForName(const QString &defName) const
     return d->m_defs.value(defName);
 }
 
-static void sortDefinitions(QVector &definitions)
-{
-    std::stable_sort(definitions.begin(), definitions.end(), [](const Definition &lhs, const Definition &rhs) {
-        return lhs.priority() > rhs.priority();
-    });
-}
-
 Definition Repository::definitionForFileName(const QString &fileName) const
 {
-    return definitionsForFileName(fileName).value(0);
+    return findHighestPriorityDefinitionIf(d->m_defs, anyWildcardMatches(fileNameFromFilePath(fileName)));
 }
 
 QVector Repository::definitionsForFileName(const QString &fileName) const
 {
-    QFileInfo fi(fileName);
-    const auto name = fi.fileName();
-
-    // use d->m_defs, sorted map by highlighting name, to be deterministic and independent of translations
-    QVector candidates;
-    for (const Definition &def : qAsConst(d->m_defs)) {
-        for (const auto &pattern : def.extensions()) {
-            if (WildcardMatcher::exactMatch(name, pattern)) {
-                candidates.push_back(def);
-                break;
-            }
-        }
-    }
-
-    sortDefinitions(candidates);
-    return candidates;
+    return findDefinitionsIf(d->m_defs, anyWildcardMatches(fileNameFromFilePath(fileName)));
 }
 
 Definition Repository::definitionForMimeType(const QString &mimeType) const
 {
-    return definitionsForMimeType(mimeType).value(0);
+    return findHighestPriorityDefinitionIf(d->m_defs, anyMimeTypeEquals(mimeType));
 }
 
 QVector Repository::definitionsForMimeType(const QString &mimeType) const
 {
-    // use d->m_defs, sorted map by highlighting name, to be deterministic and independent of translations
-    QVector candidates;
-    for (const Definition &def : qAsConst(d->m_defs)) {
-        for (const auto &matchType : def.mimeTypes()) {
-            if (mimeType == matchType) {
-                candidates.push_back(def);
-                break;
-            }
-        }
-    }
-
-    sortDefinitions(candidates);
-    return candidates;
+    return findDefinitionsIf(d->m_defs, anyMimeTypeEquals(mimeType));
 }
 
 QVector Repository::definitions() const
@@ -127,7 +154,7 @@ QVector Repository::themes() const
 
 Theme Repository::theme(const QString &themeName) const
 {
-    for (const auto &theme : qAsConst(d->m_themes)) {
+    for (const auto &theme : std::as_const(d->m_themes)) {
         if (theme.name() == themeName) {
             return theme;
         }
@@ -138,14 +165,15 @@ Theme Repository::theme(const QString &themeName) const
 
 Theme Repository::defaultTheme(Repository::DefaultTheme t) const
 {
-    if (t == DarkTheme)
+    if (t == DarkTheme) {
         return theme(QLatin1String("Breeze Dark"));
+    }
     return theme(QLatin1String("Breeze Light"));
 }
 
 Theme Repository::defaultTheme(Repository::DefaultTheme t)
 {
-    return qAsConst(*this).defaultTheme(t);
+    return std::as_const(*this).defaultTheme(t);
 }
 
 Theme Repository::themeForPalette(const QPalette &palette) const
@@ -164,7 +192,7 @@ Theme Repository::themeForPalette(const QPalette &palette) const
     if (!matchingThemes.empty()) {
         // if there's multiple, search for one with a matching highlight color
         const auto highlight = palette.color(QPalette::Highlight);
-        for (const auto &theme : qAsConst(matchingThemes)) {
+        for (const auto &theme : std::as_const(matchingThemes)) {
             auto selection = theme.editorColor(KSyntaxHighlighting::Theme::EditorColorRole::TextSelection);
             if (selection == highlight.rgb()) {
                 return theme;
@@ -179,7 +207,7 @@ Theme Repository::themeForPalette(const QPalette &palette) const
 
 Theme Repository::themeForPalette(const QPalette &palette)
 {
-    return qAsConst(*this).themeForPalette(palette);
+    return std::as_const(*this).themeForPalette(palette);
 }
 
 void RepositoryPrivate::load(Repository *repo)
@@ -189,29 +217,39 @@ void RepositoryPrivate::load(Repository *repo)
 
     // do lookup in standard paths, if not disabled
 #ifndef NO_STANDARD_PATHS
-    for (const auto &dir :
-         QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/syntax"), QStandardPaths::LocateDirectory))
+    for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
+                                                     QStringLiteral("org.kde.syntax-highlighting/syntax"),
+                                                     QStandardPaths::LocateDirectory)) {
         loadSyntaxFolder(repo, dir);
+    }
 
     // backward compatibility with Kate
-    for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory))
+    for (const auto &dir :
+         QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory)) {
         loadSyntaxFolder(repo, dir);
+    }
 #endif
 
-    // default resources are always used
-    loadSyntaxFolder(repo, QStringLiteral(":/org.kde.syntax-highlighting/syntax"));
+    // default resources are always used, this is the one location that has a index cbor file
+    loadSyntaxFolderFromIndex(repo, QStringLiteral(":/org.kde.syntax-highlighting/syntax"));
+
+    // extra resources provided by 3rdparty libraries/applications
+    loadSyntaxFolder(repo, QStringLiteral(":/org.kde.syntax-highlighting/syntax-addons"));
 
     // user given extra paths
-    for (const auto &path : qAsConst(m_customSearchPaths))
+    for (const auto &path : std::as_const(m_customSearchPaths)) {
         loadSyntaxFolder(repo, path + QStringLiteral("/syntax"));
+    }
 
     m_sortedDefs.reserve(m_defs.size());
-    for (auto it = m_defs.constBegin(); it != m_defs.constEnd(); ++it)
+    for (auto it = m_defs.constBegin(); it != m_defs.constEnd(); ++it) {
         m_sortedDefs.push_back(it.value());
+    }
     std::sort(m_sortedDefs.begin(), m_sortedDefs.end(), [](const Definition &left, const Definition &right) {
         auto comparison = left.translatedSection().compare(right.translatedSection(), Qt::CaseInsensitive);
-        if (comparison == 0)
+        if (comparison == 0) {
             comparison = left.translatedName().compare(right.translatedName(), Qt::CaseInsensitive);
+        }
         return comparison < 0;
     });
 
@@ -219,54 +257,60 @@ void RepositoryPrivate::load(Repository *repo)
 
     // do lookup in standard paths, if not disabled
 #ifndef NO_STANDARD_PATHS
-    for (const auto &dir :
-         QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/themes"), QStandardPaths::LocateDirectory))
+    for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
+                                                     QStringLiteral("org.kde.syntax-highlighting/themes"),
+                                                     QStandardPaths::LocateDirectory)) {
         loadThemeFolder(dir);
+    }
 #endif
 
     // default resources are always used
     loadThemeFolder(QStringLiteral(":/org.kde.syntax-highlighting/themes"));
 
+    // extra resources provided by 3rdparty libraries/applications
+    loadThemeFolder(QStringLiteral(":/org.kde.syntax-highlighting/themes-addons"));
+
     // user given extra paths
-    for (const auto &path : qAsConst(m_customSearchPaths))
+    for (const auto &path : std::as_const(m_customSearchPaths)) {
         loadThemeFolder(path + QStringLiteral("/themes"));
+    }
 }
 
 void RepositoryPrivate::loadSyntaxFolder(Repository *repo, const QString &path)
 {
-    if (loadSyntaxFolderFromIndex(repo, path))
-        return;
-
     QDirIterator it(path, QStringList() << QLatin1String("*.xml"), QDir::Files);
     while (it.hasNext()) {
         Definition def;
         auto defData = DefinitionData::get(def);
         defData->repo = repo;
-        if (defData->loadMetaData(it.next()))
+        if (defData->loadMetaData(it.next())) {
             addDefinition(def);
+        }
     }
 }
 
-bool RepositoryPrivate::loadSyntaxFolderFromIndex(Repository *repo, const QString &path)
+void RepositoryPrivate::loadSyntaxFolderFromIndex(Repository *repo, const QString &path)
 {
     QFile indexFile(path + QLatin1String("/index.katesyntax"));
-    if (!indexFile.open(QFile::ReadOnly))
-        return false;
+    if (!indexFile.open(QFile::ReadOnly)) {
+        return;
+    }
 
     const auto indexDoc(QCborValue::fromCbor(indexFile.readAll()));
     const auto index = indexDoc.toMap();
     for (auto it = index.begin(); it != index.end(); ++it) {
-        if (!it.value().isMap())
+        if (!it.value().isMap()) {
             continue;
+        }
         const auto fileName = QString(path + QLatin1Char('/') + it.key().toString());
         const auto defMap = it.value().toMap();
         Definition def;
         auto defData = DefinitionData::get(def);
         defData->repo = repo;
-        if (defData->loadMetaData(fileName, defMap))
+        if (defData->loadMetaData(fileName, defMap)) {
             addDefinition(def);
+        }
     }
-    return true;
 }
 
 void RepositoryPrivate::addDefinition(const Definition &def)
@@ -277,8 +321,9 @@ void RepositoryPrivate::addDefinition(const Definition &def)
         return;
     }
 
-    if (it.value().version() >= def.version())
+    if (it.value().version() >= def.version()) {
         return;
+    }
     m_defs.insert(def.name(), def);
 }
 
@@ -287,8 +332,9 @@ void RepositoryPrivate::loadThemeFolder(const QString &path)
     QDirIterator it(path, QStringList() << QLatin1String("*.theme"), QDir::Files);
     while (it.hasNext()) {
         auto themeData = std::unique_ptr(new ThemeData);
-        if (themeData->load(it.next()))
+        if (themeData->load(it.next())) {
             addTheme(Theme(themeData.release()));
+        }
     }
 }
 
@@ -307,15 +353,17 @@ void RepositoryPrivate::addTheme(const Theme &theme)
         m_themes.insert(it, theme);
         return;
     }
-    if (themeRevision(*it) < themeRevision(theme))
+    if (themeRevision(*it) < themeRevision(theme)) {
         *it = theme;
+    }
 }
 
 quint16 RepositoryPrivate::foldingRegionId(const QString &defName, const QString &foldName)
 {
     const auto it = m_foldingRegionIds.constFind(qMakePair(defName, foldName));
-    if (it != m_foldingRegionIds.constEnd())
+    if (it != m_foldingRegionIds.constEnd()) {
         return it.value();
+    }
     m_foldingRegionIds.insert(qMakePair(defName, foldName), ++m_foldingRegionId);
     return m_foldingRegionId;
 }
@@ -329,8 +377,9 @@ quint16 RepositoryPrivate::nextFormatId()
 void Repository::reload()
 {
     qCDebug(Log) << "Reloading syntax definitions!";
-    for (const auto &def : qAsConst(d->m_sortedDefs))
+    for (const auto &def : std::as_const(d->m_sortedDefs)) {
         DefinitionData::get(def)->clear();
+    }
     d->m_defs.clear();
     d->m_sortedDefs.clear();
 
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
index 323407f0081..9e19ecda566 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
@@ -86,6 +86,11 @@ class Theme;
  *    The internal resource path is ":/org.kde.syntax-highlighting/syntax".
  *    This path should never be touched by other applications.
  *
+ * -# Then, all custom files compiled into resources are loaded.
+ *    The resource path is ":/org.kde.syntax-highlighting/syntax-addons".
+ *    This path can be used by other libraries/applications to bundle specialized definitions.
+ *    Per default this path isn't used by the framework itself.
+ *
  * -# Finally, the search path can be extended by calling addCustomSearchPath().
  *    A custom search path can either be a path on disk or again a path to
  *    a Qt resource.
@@ -102,6 +107,11 @@ class Theme;
  *    The internal resource path is ":/org.kde.syntax-highlighting/themes".
  *    This path should never be touched by other applications.
  *
+ * -# Then, all custom files compiled into resources are loaded.
+ *    The resource path is ":/org.kde.syntax-highlighting/themes-addons".
+ *    This path can be used by other libraries/applications to bundle specialized themes.
+ *    Per default this path isn't used by the framework itself.
+ *
  * -# Finally, all Theme%s located in the paths added addCustomSearchPath()
  *    are loaded.
  *
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
index 447cfae6990..abc992358d6 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
@@ -29,7 +29,7 @@ public:
 
     void load(Repository *repo);
     void loadSyntaxFolder(Repository *repo, const QString &path);
-    bool loadSyntaxFolderFromIndex(Repository *repo, const QString &path);
+    void loadSyntaxFolderFromIndex(Repository *repo, const QString &path);
 
     void addDefinition(const Definition &def);
 
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
index c8d3fa0e63b..3e1160b0db3 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
@@ -34,10 +34,11 @@ static bool isHexChar(QChar c)
     return isDigit(c) || (c <= QLatin1Char('f') && QLatin1Char('a') <= c) || (c <= QLatin1Char('F') && QLatin1Char('A') <= c);
 }
 
-static int matchEscapedChar(const QString &text, int offset)
+static int matchEscapedChar(QStringView text, int offset)
 {
-    if (text.at(offset) != QLatin1Char('\\') || text.size() < offset + 2)
+    if (text.at(offset) != QLatin1Char('\\') || text.size() < offset + 2) {
         return offset;
+    }
 
     const auto c = text.at(offset + 1);
     switch (c.unicode()) {
@@ -59,8 +60,9 @@ static int matchEscapedChar(const QString &text, int offset)
     // hex encoded character
     case 'x':
         if (offset + 2 < text.size() && isHexChar(text.at(offset + 2))) {
-            if (offset + 3 < text.size() && isHexChar(text.at(offset + 3)))
+            if (offset + 3 < text.size() && isHexChar(text.at(offset + 3))) {
                 return offset + 4;
+            }
             return offset + 3;
         }
         return offset;
@@ -75,8 +77,9 @@ static int matchEscapedChar(const QString &text, int offset)
     case '6':
     case '7':
         if (offset + 2 < text.size() && isOctalChar(text.at(offset + 2))) {
-            if (offset + 3 < text.size() && isOctalChar(text.at(offset + 3)))
+            if (offset + 3 < text.size() && isOctalChar(text.at(offset + 3))) {
                 return offset + 4;
+            }
             return offset + 3;
         }
         return offset + 2;
@@ -116,26 +119,31 @@ bool Rule::load(QXmlStreamReader &reader)
     Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
 
     m_attribute = reader.attributes().value(QLatin1String("attribute")).toString();
-    if (reader.name() != QLatin1String("IncludeRules")) // IncludeRules uses this with a different semantic
+    if (reader.name() != QLatin1String("IncludeRules")) { // IncludeRules uses this with a different semantic
         m_context.parse(reader.attributes().value(QLatin1String("context")));
+    }
     m_firstNonSpace = Xml::attrToBool(reader.attributes().value(QLatin1String("firstNonSpace")));
     m_lookAhead = Xml::attrToBool(reader.attributes().value(QLatin1String("lookAhead")));
     bool colOk = false;
     m_column = reader.attributes().value(QLatin1String("column")).toInt(&colOk);
-    if (!colOk)
+    if (!colOk) {
         m_column = -1;
+    }
 
     auto regionName = reader.attributes().value(QLatin1String("beginRegion"));
-    if (!regionName.isEmpty())
+    if (!regionName.isEmpty()) {
         m_beginRegion = FoldingRegion(FoldingRegion::Begin, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString()));
+    }
     regionName = reader.attributes().value(QLatin1String("endRegion"));
-    if (!regionName.isEmpty())
+    if (!regionName.isEmpty()) {
         m_endRegion = FoldingRegion(FoldingRegion::End, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString()));
+    }
 
     auto result = doLoad(reader);
 
-    if (m_lookAhead && m_context.isStay())
+    if (m_lookAhead && m_context.isStay()) {
         result = false;
+    }
 
     // be done with this rule, skip all subelements, e.g. no longer supported sub-rules
     reader.skipCurrentElement();
@@ -184,42 +192,60 @@ void Rule::loadAdditionalWordDelimiters(QXmlStreamReader &reader)
 
 Rule::Ptr Rule::create(QStringView name)
 {
-    if (name == QLatin1String("AnyChar"))
+    if (name == QLatin1String("AnyChar")) {
         return std::make_shared();
-    if (name == QLatin1String("DetectChar"))
+    }
+    if (name == QLatin1String("DetectChar")) {
         return std::make_shared();
-    if (name == QLatin1String("Detect2Chars"))
+    }
+    if (name == QLatin1String("Detect2Chars")) {
         return std::make_shared();
-    if (name == QLatin1String("DetectIdentifier"))
+    }
+    if (name == QLatin1String("DetectIdentifier")) {
         return std::make_shared();
-    if (name == QLatin1String("DetectSpaces"))
+    }
+    if (name == QLatin1String("DetectSpaces")) {
         return std::make_shared();
-    if (name == QLatin1String("Float"))
+    }
+    if (name == QLatin1String("Float")) {
         return std::make_shared();
-    if (name == QLatin1String("Int"))
+    }
+    if (name == QLatin1String("Int")) {
         return std::make_shared();
-    if (name == QLatin1String("HlCChar"))
+    }
+    if (name == QLatin1String("HlCChar")) {
         return std::make_shared();
-    if (name == QLatin1String("HlCHex"))
+    }
+    if (name == QLatin1String("HlCHex")) {
         return std::make_shared();
-    if (name == QLatin1String("HlCOct"))
+    }
+    if (name == QLatin1String("HlCOct")) {
         return std::make_shared();
-    if (name == QLatin1String("HlCStringChar"))
+    }
+    if (name == QLatin1String("HlCStringChar")) {
         return std::make_shared();
-    if (name == QLatin1String("IncludeRules"))
+    }
+    if (name == QLatin1String("IncludeRules")) {
         return std::make_shared();
-    if (name == QLatin1String("keyword"))
+    }
+    if (name == QLatin1String("keyword")) {
         return std::make_shared();
-    if (name == QLatin1String("LineContinue"))
+    }
+    if (name == QLatin1String("LineContinue")) {
         return std::make_shared();
-    if (name == QLatin1String("RangeDetect"))
+    }
+    if (name == QLatin1String("RangeDetect")) {
         return std::make_shared();
-    if (name == QLatin1String("RegExpr"))
+    }
+    if (name == QLatin1String("RegExpr")) {
         return std::make_shared();
-    if (name == QLatin1String("StringDetect"))
+    }
+    if (name == QLatin1String("StringDetect")) {
         return std::make_shared();
-    if (name == QLatin1String("WordDetect"))
+    }
+    if (name == QLatin1String("WordDetect")) {
         return std::make_shared();
+    }
 
     qCWarning(Log) << "Unknown rule type:" << name;
     return Ptr(nullptr);
@@ -233,23 +259,26 @@ bool Rule::isWordDelimiter(QChar c) const
 bool AnyChar::doLoad(QXmlStreamReader &reader)
 {
     m_chars = reader.attributes().value(QLatin1String("String")).toString();
-    if (m_chars.size() == 1)
+    if (m_chars.size() == 1) {
         qCDebug(Log) << "AnyChar rule with just one char: use DetectChar instead.";
+    }
     return !m_chars.isEmpty();
 }
 
-MatchResult AnyChar::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (m_chars.contains(text.at(offset)))
+    if (m_chars.contains(text.at(offset))) {
         return offset + 1;
+    }
     return offset;
 }
 
 bool DetectChar::doLoad(QXmlStreamReader &reader)
 {
     const auto s = reader.attributes().value(QLatin1String("char"));
-    if (s.isEmpty())
+    if (s.isEmpty()) {
         return false;
+    }
     m_char = s.at(0);
     m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic")));
     if (m_dynamic) {
@@ -258,18 +287,21 @@ bool DetectChar::doLoad(QXmlStreamReader &reader)
     return true;
 }
 
-MatchResult DetectChar::doMatch(const QString &text, int offset, const QStringList &captures) const
+MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures) const
 {
     if (m_dynamic) {
-        if (m_captureIndex == 0 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty())
+        if (m_captureIndex == 0 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty()) {
             return offset;
-        if (text.at(offset) == captures.at(m_captureIndex).at(0))
+        }
+        if (text.at(offset) == captures.at(m_captureIndex).at(0)) {
             return offset + 1;
+        }
         return offset;
     }
 
-    if (text.at(offset) == m_char)
+    if (text.at(offset) == m_char) {
         return offset + 1;
+    }
     return offset;
 }
 
@@ -277,40 +309,46 @@ bool Detect2Char::doLoad(QXmlStreamReader &reader)
 {
     const auto s1 = reader.attributes().value(QLatin1String("char"));
     const auto s2 = reader.attributes().value(QLatin1String("char1"));
-    if (s1.isEmpty() || s2.isEmpty())
+    if (s1.isEmpty() || s2.isEmpty()) {
         return false;
+    }
     m_char1 = s1.at(0);
     m_char2 = s2.at(0);
     return true;
 }
 
-MatchResult Detect2Char::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult Detect2Char::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (text.size() - offset < 2)
+    if (text.size() - offset < 2) {
         return offset;
-    if (text.at(offset) == m_char1 && text.at(offset + 1) == m_char2)
+    }
+    if (text.at(offset) == m_char1 && text.at(offset + 1) == m_char2) {
         return offset + 2;
+    }
     return offset;
 }
 
-MatchResult DetectIdentifier::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult DetectIdentifier::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (!text.at(offset).isLetter() && text.at(offset) != QLatin1Char('_'))
+    if (!text.at(offset).isLetter() && text.at(offset) != QLatin1Char('_')) {
         return offset;
+    }
 
     for (int i = offset + 1; i < text.size(); ++i) {
         const auto c = text.at(i);
-        if (!c.isLetterOrNumber() && c != QLatin1Char('_'))
+        if (!c.isLetterOrNumber() && c != QLatin1Char('_')) {
             return i;
+        }
     }
 
     return text.size();
 }
 
-MatchResult DetectSpaces::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    while (offset < text.size() && text.at(offset).isSpace())
+    while (offset < text.size() && text.at(offset).isSpace()) {
         ++offset;
+    }
     return offset;
 }
 
@@ -320,63 +358,76 @@ bool Float::doLoad(QXmlStreamReader &reader)
     return true;
 }
 
-MatchResult Float::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+    if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) {
         return offset;
+    }
 
     auto newOffset = offset;
-    while (newOffset < text.size() && isDigit(text.at(newOffset)))
+    while (newOffset < text.size() && isDigit(text.at(newOffset))) {
         ++newOffset;
+    }
 
-    if (newOffset >= text.size() || text.at(newOffset) != QLatin1Char('.'))
+    if (newOffset >= text.size() || text.at(newOffset) != QLatin1Char('.')) {
         return offset;
+    }
     ++newOffset;
 
-    while (newOffset < text.size() && isDigit(text.at(newOffset)))
+    while (newOffset < text.size() && isDigit(text.at(newOffset))) {
         ++newOffset;
+    }
 
-    if (newOffset == offset + 1) // we only found a decimal point
+    if (newOffset == offset + 1) { // we only found a decimal point
         return offset;
+    }
 
     auto expOffset = newOffset;
-    if (expOffset >= text.size() || (text.at(expOffset) != QLatin1Char('e') && text.at(expOffset) != QLatin1Char('E')))
+    if (expOffset >= text.size() || (text.at(expOffset) != QLatin1Char('e') && text.at(expOffset) != QLatin1Char('E'))) {
         return newOffset;
+    }
     ++expOffset;
 
-    if (expOffset < text.size() && (text.at(expOffset) == QLatin1Char('+') || text.at(expOffset) == QLatin1Char('-')))
+    if (expOffset < text.size() && (text.at(expOffset) == QLatin1Char('+') || text.at(expOffset) == QLatin1Char('-'))) {
         ++expOffset;
+    }
     bool foundExpDigit = false;
     while (expOffset < text.size() && isDigit(text.at(expOffset))) {
         ++expOffset;
         foundExpDigit = true;
     }
 
-    if (!foundExpDigit)
+    if (!foundExpDigit) {
         return newOffset;
+    }
     return expOffset;
 }
 
-MatchResult HlCChar::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (text.size() < offset + 3)
+    if (text.size() < offset + 3) {
         return offset;
+    }
 
-    if (text.at(offset) != QLatin1Char('\'') || text.at(offset + 1) == QLatin1Char('\''))
+    if (text.at(offset) != QLatin1Char('\'') || text.at(offset + 1) == QLatin1Char('\'')) {
         return offset;
+    }
 
     auto newOffset = matchEscapedChar(text, offset + 1);
     if (newOffset == offset + 1) {
-        if (text.at(newOffset) == QLatin1Char('\\'))
+        if (text.at(newOffset) == QLatin1Char('\\')) {
             return offset;
-        else
+        } else {
             ++newOffset;
+        }
     }
-    if (newOffset >= text.size())
+    if (newOffset >= text.size()) {
         return offset;
+    }
 
-    if (text.at(newOffset) == QLatin1Char('\''))
+    if (text.at(newOffset) == QLatin1Char('\'')) {
         return newOffset + 1;
+    }
 
     return offset;
 }
@@ -387,23 +438,28 @@ bool HlCHex::doLoad(QXmlStreamReader &reader)
     return true;
 }
 
-MatchResult HlCHex::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+    if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) {
         return offset;
+    }
 
-    if (text.size() < offset + 3)
+    if (text.size() < offset + 3) {
         return offset;
+    }
 
-    if (text.at(offset) != QLatin1Char('0') || (text.at(offset + 1) != QLatin1Char('x') && text.at(offset + 1) != QLatin1Char('X')))
+    if (text.at(offset) != QLatin1Char('0') || (text.at(offset + 1) != QLatin1Char('x') && text.at(offset + 1) != QLatin1Char('X'))) {
         return offset;
+    }
 
-    if (!isHexChar(text.at(offset + 2)))
+    if (!isHexChar(text.at(offset + 2))) {
         return offset;
+    }
 
     offset += 3;
-    while (offset < text.size() && isHexChar(text.at(offset)))
+    while (offset < text.size() && isHexChar(text.at(offset))) {
         ++offset;
+    }
 
     // TODO Kate matches U/L suffix, QtC does not?
 
@@ -416,28 +472,33 @@ bool HlCOct::doLoad(QXmlStreamReader &reader)
     return true;
 }
 
-MatchResult HlCOct::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+    if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) {
         return offset;
+    }
 
-    if (text.size() < offset + 2)
+    if (text.size() < offset + 2) {
         return offset;
+    }
 
-    if (text.at(offset) != QLatin1Char('0'))
+    if (text.at(offset) != QLatin1Char('0')) {
         return offset;
+    }
 
-    if (!isOctalChar(text.at(offset + 1)))
+    if (!isOctalChar(text.at(offset + 1))) {
         return offset;
+    }
 
     offset += 2;
-    while (offset < text.size() && isOctalChar(text.at(offset)))
+    while (offset < text.size() && isOctalChar(text.at(offset))) {
         ++offset;
+    }
 
     return offset;
 }
 
-MatchResult HlCStringChar::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringList &) const
 {
     return matchEscapedChar(text, offset);
 }
@@ -461,17 +522,19 @@ bool IncludeRules::doLoad(QXmlStreamReader &reader)
 {
     const auto s = reader.attributes().value(QLatin1String("context"));
     const auto split = s.split(QString::fromLatin1("##"), Qt::KeepEmptyParts);
-    if (split.isEmpty())
+    if (split.isEmpty()) {
         return false;
+    }
     m_contextName = split.at(0).toString();
-    if (split.size() > 1)
+    if (split.size() > 1) {
         m_defName = split.at(1).toString();
+    }
     m_includeAttribute = Xml::attrToBool(reader.attributes().value(QLatin1String("includeAttrib")));
 
     return !m_contextName.isEmpty() || !m_defName.isEmpty();
 }
 
-MatchResult IncludeRules::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &) const
 {
     Q_UNUSED(text);
     qCWarning(Log) << "Unresolved include rule for" << m_contextName << "##" << m_defName;
@@ -484,13 +547,15 @@ bool Int::doLoad(QXmlStreamReader &reader)
     return true;
 }
 
-MatchResult Int::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+    if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) {
         return offset;
+    }
 
-    while (offset < text.size() && isDigit(text.at(offset)))
+    while (offset < text.size() && isDigit(text.at(offset))) {
         ++offset;
+    }
     return offset;
 }
 
@@ -522,21 +587,24 @@ bool KeywordListRule::doLoad(QXmlStreamReader &reader)
     return !m_keywordList->isEmpty();
 }
 
-MatchResult KeywordListRule::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &) const
 {
     auto newOffset = offset;
-    while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset)))
+    while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset))) {
         ++newOffset;
-    if (newOffset == offset)
+    }
+    if (newOffset == offset) {
         return offset;
+    }
 
     if (m_hasCaseSensitivityOverride) {
-        if (m_keywordList->contains(QStringView(text).mid(offset, newOffset - offset),
-                                    m_caseSensitivityOverride))
+        if (m_keywordList->contains(text.mid(offset, newOffset - offset), m_caseSensitivityOverride)) {
             return newOffset;
+        }
     } else {
-        if (m_keywordList->contains(QStringView(text).mid(offset, newOffset - offset)))
+        if (m_keywordList->contains(text.mid(offset, newOffset - offset))) {
             return newOffset;
+        }
     }
 
     // we don't match, but we can skip until newOffset as we can't start a keyword in-between
@@ -546,17 +614,19 @@ MatchResult KeywordListRule::doMatch(const QString &text, int offset, const QStr
 bool LineContinue::doLoad(QXmlStreamReader &reader)
 {
     const auto s = reader.attributes().value(QLatin1String("char"));
-    if (s.isEmpty())
+    if (s.isEmpty()) {
         m_char = QLatin1Char('\\');
-    else
+    } else {
         m_char = s.at(0);
+    }
     return true;
 }
 
-MatchResult LineContinue::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (offset == text.size() - 1 && text.at(offset) == m_char)
+    if (offset == text.size() - 1 && text.at(offset) == m_char) {
         return offset + 1;
+    }
     return offset;
 }
 
@@ -564,24 +634,28 @@ bool RangeDetect::doLoad(QXmlStreamReader &reader)
 {
     const auto s1 = reader.attributes().value(QLatin1String("char"));
     const auto s2 = reader.attributes().value(QLatin1String("char1"));
-    if (s1.isEmpty() || s2.isEmpty())
+    if (s1.isEmpty() || s2.isEmpty()) {
         return false;
+    }
     m_begin = s1.at(0);
     m_end = s2.at(0);
     return true;
 }
 
-MatchResult RangeDetect::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (text.size() - offset < 2)
+    if (text.size() - offset < 2) {
         return offset;
-    if (text.at(offset) != m_begin)
+    }
+    if (text.at(offset) != m_begin) {
         return offset;
+    }
 
     auto newOffset = offset + 1;
     while (newOffset < text.size()) {
-        if (text.at(newOffset) == m_end)
+        if (text.at(newOffset) == m_end) {
             return newOffset + 1;
+        }
         ++newOffset;
     }
     return offset;
@@ -596,7 +670,9 @@ bool RegExpr::doLoad(QXmlStreamReader &reader)
     m_regexp.setPatternOptions((isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption)
                                | (isCaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption)
                                // DontCaptureOption is removed by resolvePostProcessing() when necessary
-                               | QRegularExpression::DontCaptureOption);
+                               | QRegularExpression::DontCaptureOption
+                               // ensure Unicode support is enabled
+                               | QRegularExpression::UseUnicodePropertiesOption);
 
     m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic")));
 
@@ -605,8 +681,9 @@ bool RegExpr::doLoad(QXmlStreamReader &reader)
 
 void KSyntaxHighlighting::RegExpr::resolvePostProcessing()
 {
-    if (m_isResolved)
+    if (m_isResolved) {
         return;
+    }
 
     m_isResolved = true;
     bool hasCapture = false;
@@ -641,7 +718,7 @@ void KSyntaxHighlighting::RegExpr::resolvePostProcessing()
     }
 }
 
-MatchResult RegExpr::doMatch(const QString &text, int offset, const QStringList &captures) const
+MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &captures) const
 {
     /**
      * for dynamic case: create new pattern with right instantiation
@@ -683,16 +760,16 @@ bool StringDetect::doLoad(QXmlStreamReader &reader)
     return !m_string.isEmpty();
 }
 
-MatchResult StringDetect::doMatch(const QString &text, int offset, const QStringList &captures) const
+MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const
 {
     /**
      * for dynamic case: create new pattern with right instantiation
      */
     const auto &pattern = m_dynamic ? replaceCaptures(m_string, captures, false) : m_string;
 
-    if (offset + pattern.size() <= text.size()
-        && QStringView(text).mid(offset, pattern.size()).compare(pattern, m_caseSensitivity) == 0)
+    if (offset + pattern.size() <= text.size() && text.mid(offset, pattern.size()).compare(pattern, m_caseSensitivity) == 0) {
         return offset + pattern.size();
+    }
     return offset;
 }
 
@@ -704,23 +781,27 @@ bool WordDetect::doLoad(QXmlStreamReader &reader)
     return !m_word.isEmpty();
 }
 
-MatchResult WordDetect::doMatch(const QString &text, int offset, const QStringList &) const
+MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &) const
 {
-    if (text.size() - offset < m_word.size())
+    if (text.size() - offset < m_word.size()) {
         return offset;
+    }
 
     /**
      * detect delimiter characters on the inner and outer boundaries of the string
      * NOTE: m_word isn't empty
      */
-    if (offset > 0 && !isWordDelimiter(text.at(offset - 1)) && !isWordDelimiter(text.at(offset)))
+    if (offset > 0 && !isWordDelimiter(text.at(offset - 1)) && !isWordDelimiter(text.at(offset))) {
         return offset;
+    }
 
-    if (QStringView(text).mid(offset, m_word.size()).compare(m_word, m_caseSensitivity) != 0)
+    if (text.mid(offset, m_word.size()).compare(m_word, m_caseSensitivity) != 0) {
         return offset;
+    }
 
-    if (text.size() == offset + m_word.size() || isWordDelimiter(text.at(offset + m_word.size())) || isWordDelimiter(text.at(offset + m_word.size() - 1)))
+    if (text.size() == offset + m_word.size() || isWordDelimiter(text.at(offset + m_word.size())) || isWordDelimiter(text.at(offset + m_word.size() - 1))) {
         return offset + m_word.size();
+    }
 
     return offset;
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
index 22c786eaa27..374eb87dfaf 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
@@ -87,7 +87,7 @@ public:
     {
     }
 
-    virtual MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const = 0;
+    virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const = 0;
 
     static Rule::Ptr create(QStringView name);
 
@@ -121,58 +121,58 @@ protected:
     bool m_dynamic = false;
 };
 
-class AnyChar : public Rule
+class AnyChar final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 
 private:
     QString m_chars;
 };
 
-class DetectChar : public Rule
+class DetectChar final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
 
 private:
     QChar m_char;
     int m_captureIndex = 0;
 };
 
-class Detect2Char : public Rule
+class Detect2Char final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
 
 private:
     QChar m_char1;
     QChar m_char2;
 };
 
-class DetectIdentifier : public Rule
+class DetectIdentifier final : public Rule
 {
 protected:
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 };
 
-class DetectSpaces : public Rule
+class DetectSpaces final : public Rule
 {
 protected:
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 };
 
-class Float : public Rule
+class Float final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 };
 
-class IncludeRules : public Rule
+class IncludeRules final : public Rule
 {
 public:
     QString contextName() const;
@@ -181,7 +181,7 @@ public:
 
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 
 private:
     QString m_contextName;
@@ -189,44 +189,44 @@ private:
     bool m_includeAttribute;
 };
 
-class Int : public Rule
+class Int final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
 };
 
-class HlCChar : public Rule
+class HlCChar final : public Rule
 {
 protected:
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 };
 
-class HlCHex : public Rule
+class HlCHex final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 };
 
-class HlCOct : public Rule
+class HlCOct final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 };
 
-class HlCStringChar : public Rule
+class HlCStringChar final : public Rule
 {
 protected:
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 };
 
-class KeywordListRule : public Rule
+class KeywordListRule final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 
 private:
     KeywordList *m_keywordList;
@@ -234,55 +234,55 @@ private:
     Qt::CaseSensitivity m_caseSensitivityOverride;
 };
 
-class LineContinue : public Rule
+class LineContinue final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 
 private:
     QChar m_char;
 };
 
-class RangeDetect : public Rule
+class RangeDetect final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
 
 private:
     QChar m_begin;
     QChar m_end;
 };
 
-class RegExpr : public Rule
+class RegExpr final : public Rule
 {
 protected:
     void resolvePostProcessing() override;
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
 
 private:
     QRegularExpression m_regexp;
     bool m_isResolved = false;
 };
 
-class StringDetect : public Rule
+class StringDetect final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
 
 private:
     QString m_string;
     Qt::CaseSensitivity m_caseSensitivity;
 };
 
-class WordDetect : public Rule
+class WordDetect final : public Rule
 {
 protected:
     bool doLoad(QXmlStreamReader &reader) override;
-    MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
 
 private:
     QString m_word;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
index f9b4f4b4ab0..ea21fef2151 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
@@ -104,7 +104,8 @@ bool State::operator!=(const State &other) const
 
 bool State::indentationBasedFoldingEnabled() const
 {
-    if (!d || d->m_contextStack.isEmpty())
+    if (!d || d->m_contextStack.isEmpty()) {
         return false;
+    }
     return d->m_contextStack.last().first->indentationBasedFoldingEnabled();
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
index d0c4ee98ae8..41551e96da5 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
@@ -37,11 +37,13 @@ public:
 FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock &startBlock)
 {
     const auto data = dynamic_cast(startBlock.userData());
-    if (!data)
+    if (!data) {
         return FoldingRegion();
+    }
     for (int i = data->foldingRegions.size() - 1; i >= 0; --i) {
-        if (data->foldingRegions.at(i).type() == FoldingRegion::Begin)
+        if (data->foldingRegions.at(i).type() == FoldingRegion::Begin) {
             return data->foldingRegions.at(i);
+        }
     }
     return FoldingRegion();
 }
@@ -68,8 +70,9 @@ void SyntaxHighlighter::setDefinition(const Definition &def)
 {
     const auto needsRehighlight = definition() != def;
     AbstractHighlighter::setDefinition(def);
-    if (needsRehighlight)
+    if (needsRehighlight) {
         rehighlight();
+    }
 }
 
 bool SyntaxHighlighter::startsFoldingRegion(const QTextBlock &startBlock) const
@@ -86,17 +89,21 @@ QTextBlock SyntaxHighlighter::findFoldingRegionEnd(const QTextBlock &startBlock)
     while (block.isValid()) {
         block = block.next();
         const auto data = dynamic_cast(block.userData());
-        if (!data)
+        if (!data) {
             continue;
+        }
         for (auto it = data->foldingRegions.constBegin(); it != data->foldingRegions.constEnd(); ++it) {
-            if ((*it).id() != region.id())
+            if ((*it).id() != region.id()) {
                 continue;
-            if ((*it).type() == FoldingRegion::End)
+            }
+            if ((*it).type() == FoldingRegion::End) {
                 --depth;
-            else if ((*it).type() == FoldingRegion::Begin)
+            } else if ((*it).type() == FoldingRegion::Begin) {
                 ++depth;
-            if (depth == 0)
+            }
+            if (depth == 0) {
                 return block;
+            }
         }
     }
 
@@ -111,8 +118,9 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
     if (currentBlock().position() > 0) {
         const auto prevBlock = currentBlock().previous();
         const auto prevData = dynamic_cast(prevBlock.userData());
-        if (prevData)
+        if (prevData) {
             state = prevData->state;
+        }
     }
     d->foldingRegions.clear();
     state = highlightLine(text, state);
@@ -126,35 +134,43 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
         return;
     }
 
-    if (data->state == state && data->foldingRegions == d->foldingRegions) // we ended up in the same state, so we are done here
+    if (data->state == state && data->foldingRegions == d->foldingRegions) { // we ended up in the same state, so we are done here
         return;
+    }
     data->state = state;
     data->foldingRegions = d->foldingRegions;
 
     const auto nextBlock = currentBlock().next();
-    if (nextBlock.isValid())
+    if (nextBlock.isValid()) {
         QMetaObject::invokeMethod(this, "rehighlightBlock", Qt::QueuedConnection, Q_ARG(QTextBlock, nextBlock));
+    }
 }
 
 void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format)
 {
-    if (length == 0)
+    if (length == 0) {
         return;
+    }
 
     QTextCharFormat tf;
     // always set the foreground color to avoid palette issues
     tf.setForeground(format.textColor(theme()));
 
-    if (format.hasBackgroundColor(theme()))
+    if (format.hasBackgroundColor(theme())) {
         tf.setBackground(format.backgroundColor(theme()));
-    if (format.isBold(theme()))
+    }
+    if (format.isBold(theme())) {
         tf.setFontWeight(QFont::Bold);
-    if (format.isItalic(theme()))
+    }
+    if (format.isItalic(theme())) {
         tf.setFontItalic(true);
-    if (format.isUnderline(theme()))
+    }
+    if (format.isUnderline(theme())) {
         tf.setFontUnderline(true);
-    if (format.isStrikeThrough(theme()))
+    }
+    if (format.isStrikeThrough(theme())) {
         tf.setFontStrikeOut(true);
+    }
 
     QSyntaxHighlighter::setFormat(offset, length, tf);
 }
@@ -165,13 +181,15 @@ void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion regio
     Q_UNUSED(length);
     Q_D(SyntaxHighlighter);
 
-    if (region.type() == FoldingRegion::Begin)
+    if (region.type() == FoldingRegion::Begin) {
         d->foldingRegions.push_back(region);
+    }
 
     if (region.type() == FoldingRegion::End) {
         for (int i = d->foldingRegions.size() - 1; i >= 0; --i) {
-            if (d->foldingRegions.at(i).id() != region.id() || d->foldingRegions.at(i).type() != FoldingRegion::Begin)
+            if (d->foldingRegions.at(i).id() != region.id() || d->foldingRegions.at(i).type() != FoldingRegion::Begin) {
                 continue;
+            }
             d->foldingRegions.remove(i);
             return;
         }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
index 076e8d0318b..37f9de1694b 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
@@ -64,6 +64,8 @@ class RepositoryPrivate;
 class KSYNTAXHIGHLIGHTING_EXPORT Theme
 {
     Q_GADGET
+    Q_PROPERTY(QString name READ name)
+    Q_PROPERTY(QString translatedName READ translatedName)
 public:
     // TODO KF6:
     // - make TextStyle an enum class
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
index 2919a31a6e6..f9c386bc2a3 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
@@ -160,8 +160,9 @@ bool ThemeData::load(const QString &filePath)
     for (auto it = customStyles.begin(); it != customStyles.end(); ++it) {
         const auto obj = it.value().toObject();
         auto &overrideStyle = m_textStyleOverrides[it.key()];
-        for (auto it2 = obj.begin(); it2 != obj.end(); ++it2)
+        for (auto it2 = obj.begin(); it2 != obj.end(); ++it2) {
             overrideStyle.insert(it2.key(), readThemeData(it2.value().toObject()));
+        }
     }
 
     return true;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp
index 82d3e4ea80b..98daff19d6e 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp
@@ -4,14 +4,16 @@
     SPDX-License-Identifier: MIT
 */
 
-#include "wildcardmatcher_p.h"
+#include "wildcardmatcher.h"
 
 using namespace KSyntaxHighlighting;
 
 #include 
-#include 
+#include 
 
-static bool exactMatch(const QString &candidate, const QString &wildcard, int candidatePosFromRight, int wildcardPosFromRight, bool caseSensitive = true)
+namespace
+{
+bool wildcardMatch(QStringView candidate, QStringView wildcard, int candidatePosFromRight, int wildcardPosFromRight)
 {
     for (; wildcardPosFromRight >= 0; wildcardPosFromRight--) {
         const auto ch = wildcard.at(wildcardPosFromRight).unicode();
@@ -27,7 +29,7 @@ static bool exactMatch(const QString &candidate, const QString &wildcard, int ca
 
             // Eat all we can and go back as far as we have to
             for (int j = -1; j <= candidatePosFromRight; j++) {
-                if (exactMatch(candidate, wildcard, j, wildcardPosFromRight - 1)) {
+                if (wildcardMatch(candidate, wildcard, j, wildcardPosFromRight - 1)) {
                     return true;
                 }
             }
@@ -47,18 +49,19 @@ static bool exactMatch(const QString &candidate, const QString &wildcard, int ca
             }
 
             const auto candidateCh = candidate.at(candidatePosFromRight).unicode();
-            const auto match = caseSensitive ? (candidateCh == ch) : (QChar::toLower(candidateCh) == QChar::toLower(ch));
-            if (match) {
+            if (candidateCh == ch) {
                 candidatePosFromRight--;
             } else {
                 return false;
             }
         }
     }
-    return true;
+    return candidatePosFromRight == -1;
 }
 
-bool WildcardMatcher::exactMatch(const QString &candidate, const QString &wildcard, bool caseSensitive)
+} // unnamed namespace
+
+bool WildcardMatcher::exactMatch(QStringView candidate, QStringView wildcard)
 {
-    return ::exactMatch(candidate, wildcard, candidate.length() - 1, wildcard.length() - 1, caseSensitive);
+    return ::wildcardMatch(candidate, wildcard, candidate.length() - 1, wildcard.length() - 1);
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.h b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.h
new file mode 100644
index 00000000000..4042de37886
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.h
@@ -0,0 +1,33 @@
+/*
+    SPDX-FileCopyrightText: 2007 Sebastian Pipping 
+
+    SPDX-License-Identifier: MIT
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_H
+#define KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include 
+
+namespace KSyntaxHighlighting
+{
+namespace WildcardMatcher
+{
+/**
+ * Matches a string against a given wildcard case-sensitively.
+ * The wildcard supports '*' (".*" in regex) and '?' ("." in regex), not more.
+ *
+ * @param candidate       Text to match
+ * @param wildcard        Wildcard to use
+ * @return                True for an exact match, false otherwise
+ *
+ * @since 5.86
+ */
+KSYNTAXHIGHLIGHTING_EXPORT bool exactMatch(QStringView candidate, QStringView wildcard);
+}
+
+}
+
+#endif // KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
index 634eeb70bb3..f9079ea1f3d 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
@@ -11,15 +11,17 @@ using namespace KSyntaxHighlighting;
 WordDelimiters::WordDelimiters()
     : asciiDelimiters{}
 {
-    for (const char *p = "\t !%&()*+,-./:;<=>?[\\]^{|}~"; *p; ++p)
+    for (const char *p = "\t !%&()*+,-./:;<=>?[\\]^{|}~"; *p; ++p) {
         // int(*p) fix -Wchar-subscripts
         asciiDelimiters[int(*p)] = true;
+    }
 }
 
 bool WordDelimiters::contains(QChar c) const
 {
-    if (c.unicode() < 128)
+    if (c.unicode() < 128) {
         return asciiDelimiters[c.unicode()];
+    }
     // perf tells contains is MUCH faster than binary search here, very short array
     return notAsciiDelimiters.contains(c);
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
index 3fa5db10a44..c1afaaa6bb0 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
@@ -12,7 +12,7 @@
 namespace KSyntaxHighlighting
 {
 /**
- * Repesents a list of character that separates 2 words.
+ * Represents a list of character that separates 2 words.
  *
  * Default delimiters are .():!+*,-<=>%&/;?[]^{|}~\, space (' ') and tabulator ('\t').
  *
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h
index 5aae9eebb51..2e1dd25cc82 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h
@@ -17,7 +17,7 @@ namespace Xml
 /** Parse a xs:boolean attribute. */
 inline bool attrToBool(QStringView str)
 {
-    return str == QLatin1String("1") || str.compare(QString("true"), Qt::CaseInsensitive) == 0;
+    return str == QStringLiteral("1") || str.compare(QStringLiteral("true"), Qt::CaseInsensitive) == 0;
 }
 
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.pro b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.pro
index 333af297a84..e9354a2f69a 100644
--- a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.pro
+++ b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.pro
@@ -3,7 +3,7 @@ include(autogenerated/autogenerated.pri)
 
 QT += network
 
-DEFINES += KSYNTAXHIGHLIGHTING_LIBRARY
+DEFINES += KF5SyntaxHighlighting_EXPORTS
 
 RESOURCES += \
     data/themes/theme-data.qrc
diff --git a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
index 27b5987e1a8..985264440f7 100644
--- a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
+++ b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
@@ -25,7 +25,7 @@ Project {
         name: "KSyntaxHighlighting_bundled"
         condition: !qtc.preferSystemSyntaxHighlighting || !Qt.KSyntaxHighlighting.present
 
-        cpp.defines: base.concat("KSYNTAXHIGHLIGHTING_LIBRARY")
+        cpp.defines: base.concat("KF5SyntaxHighlighting_EXPORTS")
         cpp.includePaths: [
             product.sourceDirectory + "/src/lib/",
             product.sourceDirectory + "/autogenerated/src/lib/",
@@ -66,7 +66,6 @@ Project {
                 "htmlhighlighter.h",
                 "keywordlist.cpp",
                 "keywordlist_p.h",
-                "ksyntaxhighlighting_export.h",
                 "matchresult_p.h",
                 "repository.cpp",
                 "repository.h",

From 8c86b9bca17da149bb6668960af2da8f13d88f93 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Fri, 15 Oct 2021 14:42:17 +0200
Subject: [PATCH 090/117] CppEditor: Make sure fallback project part is up to
 date

... with regards to the session include paths.
Amends 0636238429.

Fixes: QTCREATORBUG-26323
Change-Id: I8e2cd5f5e87d9dc3d2df3f943e13599bc7139768
Reviewed-by: David Schulz 
---
 src/plugins/clangcodemodel/clangmodelmanagersupport.cpp | 4 ----
 src/plugins/cppeditor/cppmodelmanager.cpp               | 4 ++++
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
index 52be361305a..5be1f2c83cd 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
@@ -483,10 +483,6 @@ void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
 
         // TODO: Ensure that not fully loaded documents are updated?
 
-        // TODO: If the file does not belong to any project and it is a header file,
-        //       it might make sense to check whether the file is included by any file
-        //       that does belong to a project, and if so, use the respective client
-        //       instead. Is this feasible?
         ProjectExplorer::Project * const project
                 = ProjectExplorer::SessionManager::projectForFile(document->filePath());
         if (ClangdClient * const client = clientForProject(project))
diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp
index 40b37263d89..4ddd690b42a 100644
--- a/src/plugins/cppeditor/cppmodelmanager.cpp
+++ b/src/plugins/cppeditor/cppmodelmanager.cpp
@@ -694,6 +694,10 @@ CppModelManager::CppModelManager()
 
     connect(KitManager::instance(), &KitManager::kitsChanged, this,
             &CppModelManager::setupFallbackProjectPart);
+    connect(this, &CppModelManager::projectPartsRemoved, this,
+            &CppModelManager::setupFallbackProjectPart);
+    connect(this, &CppModelManager::projectPartsUpdated, this,
+            &CppModelManager::setupFallbackProjectPart);
     setupFallbackProjectPart();
 
     qRegisterMetaType("CPlusPlus::Document::Ptr");

From 5cdce37ea4d9ae012a504635b4c47679e4b8bdad Mon Sep 17 00:00:00 2001
From: Mahmoud Badri 
Date: Tue, 19 Oct 2021 14:02:37 +0300
Subject: [PATCH 091/117] QmlDesigner: Refactor the code for adding assets

Change-Id: I25ddfb6df40494eee92d2d90faf3e90c15a82c3e
Reviewed-by: Samuel Ghinet 
Reviewed-by: Miikka Heikkinen 
---
 .../itemlibrary/itemlibrarywidget.cpp         | 79 ++++++++-----------
 1 file changed, 34 insertions(+), 45 deletions(-)

diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index de15fde7cf3..bd20722206e 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
@@ -560,45 +560,31 @@ void ItemLibraryWidget::addImportForItem(const QString &importUrl)
 
 void ItemLibraryWidget::addResources(const QStringList &files)
 {
-    auto document = QmlDesignerPlugin::instance()->currentDesignDocument();
+    DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
 
     QTC_ASSERT(document, return);
 
-    QList handlers = QmlDesignerPlugin::instance()->viewManager().designerActionManager().addResourceHandler();
-
-    QMultiMap map;
-    for (const AddResourceHandler &handler : handlers) {
-        map.insert(handler.category, handler.filter);
-    }
-
-    QMap reverseMap;
-    for (const AddResourceHandler &handler : handlers) {
-        reverseMap.insert(handler.filter, handler.category);
-    }
-
-    QMap priorities;
-    for (const AddResourceHandler &handler : handlers) {
-        priorities.insert(handler.category, handler.piority);
-    }
-
-    QStringList sortedKeys = map.uniqueKeys();
-    Utils::sort(sortedKeys, [&priorities](const QString &first,
-                const QString &second){
-        return priorities.value(first) < priorities.value(second);
-    });
+    const QList handlers = QmlDesignerPlugin::instance()->viewManager()
+                                                   .designerActionManager().addResourceHandler();
 
     QStringList fileNames = files;
-    if (fileNames.isEmpty()) {
-        QStringList filters;
-
-        for (const QString &key : qAsConst(sortedKeys)) {
-            QString str = key + " (";
-            str.append(map.values(key).join(" "));
-            str.append(")");
-            filters.append(str);
+    if (fileNames.isEmpty()) { // if no files, show the "add assets" dialog
+        QMultiMap map;
+        QHash priorities;
+        for (const AddResourceHandler &handler : handlers) {
+            map.insert(handler.category, handler.filter);
+            priorities.insert(handler.category, handler.piority);
         }
 
-        filters.prepend(tr("All Files (%1)").arg(map.values().join(" ")));
+        QStringList sortedKeys = map.uniqueKeys();
+        Utils::sort(sortedKeys, [&priorities](const QString &first, const QString &second) {
+            return priorities.value(first) < priorities.value(second);
+        });
+
+        QStringList filters { tr("All Files (%1)").arg(map.values().join(' ')) };
+        QString filterTemplate = "%1 (%2)";
+        for (const QString &key : qAsConst(sortedKeys))
+            filters.append(filterTemplate.arg(key, map.values(key).join(' ')));
 
         static QString lastDir;
         const QString currentDir = lastDir.isEmpty() ? document->fileName().parentDir().toString() : lastDir;
@@ -616,24 +602,27 @@ void ItemLibraryWidget::addResources(const QStringList &files)
         }
     }
 
-    QMultiMap partitionedFileNames;
+    QHash filterToCategory;
+    QHash categoryToOperation;
+    for (const AddResourceHandler &handler : handlers) {
+        filterToCategory.insert(handler.filter, handler.category);
+        categoryToOperation.insert(handler.category, handler.operation);
+    }
+
+    QMultiMap categoryFileNames; // filenames grouped by category
 
     for (const QString &fileName : qAsConst(fileNames)) {
         const QString suffix = "*." + QFileInfo(fileName).suffix().toLower();
-        const QString category = reverseMap.value(suffix);
-        partitionedFileNames.insert(category, fileName);
+        const QString category = filterToCategory.value(suffix);
+        categoryFileNames.insert(category, fileName);
     }
 
-    for (const QString &category : partitionedFileNames.uniqueKeys()) {
-         for (const AddResourceHandler &handler : handlers) {
-             QStringList fileNames = partitionedFileNames.values(category);
-             if (handler.category == category) {
-                 QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category);
-                 if (!handler.operation(fileNames, document->fileName().parentDir().toString()))
-                     Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), tr("Could not add %1 to project.").arg(fileNames.join(" ")));
-                 break;
-             }
-         }
+    for (const QString &category : categoryFileNames.uniqueKeys()) {
+        QStringList fileNames = categoryFileNames.values(category);
+        AddResourceOperation operation = categoryToOperation.value(category);
+        QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category);
+        if (!operation(fileNames, document->fileName().parentDir().toString()))
+            Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), tr("Could not add %1 to project.").arg(fileNames.join(' ')));
     }
 }
 

From d40fa5b353251c2277353a49a74fe91c9a6592d2 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Tue, 19 Oct 2021 12:07:54 +0200
Subject: [PATCH 092/117] LSP: Allow users to see timing data

It's often interesting to know how long it takes for a reply to a
request to come in. While that data is in principle already available
from the inspector, a dedicated logging category gives much quicker
results.

Change-Id: Idd43c6e69422140863a7adaa33a7bc17dd8e6492
Reviewed-by: David Schulz 
---
 src/libs/languageserverprotocol/jsonrpcmessages.cpp | 7 +++++++
 src/libs/languageserverprotocol/jsonrpcmessages.h   | 9 ++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.cpp b/src/libs/languageserverprotocol/jsonrpcmessages.cpp
index 64045f1e3af..2b71d34a754 100644
--- a/src/libs/languageserverprotocol/jsonrpcmessages.cpp
+++ b/src/libs/languageserverprotocol/jsonrpcmessages.cpp
@@ -37,6 +37,7 @@
 #include 
 
 namespace LanguageServerProtocol {
+Q_LOGGING_CATEGORY(timingLog, "qtc.languageserverprotocol.timing", QtWarningMsg)
 
 constexpr const char CancelRequest::methodName[];
 
@@ -148,4 +149,10 @@ CancelRequest::CancelRequest(const CancelParameter ¶ms)
     : Notification(methodName, params)
 { }
 
+void logElapsedTime(const QString &method, const QElapsedTimer &t)
+{
+    qCDebug(timingLog) << "received server reply to" << method
+                       << "after" << t.elapsed() << "ms";
+}
+
 } // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.h b/src/libs/languageserverprotocol/jsonrpcmessages.h
index bb20ca8a3cd..010bc770f8a 100644
--- a/src/libs/languageserverprotocol/jsonrpcmessages.h
+++ b/src/libs/languageserverprotocol/jsonrpcmessages.h
@@ -34,6 +34,7 @@
 #include 
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -294,6 +295,8 @@ public:
     { return JsonRpcMessage::isValid(errorMessage) && id().isValid(); }
 };
 
+void LANGUAGESERVERPROTOCOL_EXPORT logElapsedTime(const QString &method, const QElapsedTimer &t);
+
 template 
 class Request : public Notification
 {
@@ -316,9 +319,13 @@ public:
 
     Utils::optional responseHandler() const final
     {
-        auto callback = [callback = m_callBack](const QByteArray &content, QTextCodec *codec) {
+        QElapsedTimer timer;
+        timer.start();
+        auto callback = [callback = m_callBack, method = this->method(), t = std::move(timer)]
+                (const QByteArray &content, QTextCodec *codec) {
             if (!callback)
                 return;
+            logElapsedTime(method, t);
             QString parseError;
             const QJsonObject &object = JsonRpcMessageHandler::toJsonObject(content,
                                                                             codec,

From 39b36bf7734d47482020b9a5d22a4bf9aad42ba0 Mon Sep 17 00:00:00 2001
From: Jarek Kobus 
Date: Thu, 14 Oct 2021 14:36:53 +0200
Subject: [PATCH 093/117] Remove unneeded terminating of failed process

Since we employ QtcProcess, the reaping of possibly
running process is done internally by QtcProcess already.

Change-Id: Ie65314a4aecf5bb1808b0f2c46a50503d82fd6fb
Reviewed-by: Eike Ziller 
---
 src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
index d1c9d9a22b4..4eb6fdc97fc 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
@@ -934,18 +934,10 @@ void CMakeBuildSystem::runCTest()
         process.setCommand(cmd);
         process.start();
 
-        if (!process.waitForStarted(1000) || !process.waitForFinished()) {
-            if (process.state() == QProcess::NotRunning)
-                return;
-            process.terminate();
-            if (process.waitForFinished(1000))
-                return;
-            process.kill();
-            process.waitForFinished(1000);
+        if (!process.waitForStarted(1000) || !process.waitForFinished()
+                || process.exitCode() || process.exitStatus() != QProcess::NormalExit) {
             return;
         }
-        if (process.exitCode() || process.exitStatus() != QProcess::NormalExit)
-            return;
         futureInterface.reportResult(process.readAllStandardOutput());
     });
 

From 57b5cd69b922bb377f956ce13c9e3124f1e65784 Mon Sep 17 00:00:00 2001
From: Eike Ziller 
Date: Mon, 18 Oct 2021 11:00:52 +0200
Subject: [PATCH 094/117] Fix build with C++20

"erase" without namespace conflicts with std::erase, with the latter
taking precedence.

Amends 9929d3dd7332ae6509e53c60d60b7f053e7ec92f

Fixes: QTCREATORBUG-26386
Change-Id: I7fa64827ad61f1da262ce48082854975bc431c69
Reviewed-by: Christian Kandeler 
---
 src/plugins/projectexplorer/project.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
index a49011bc41f..620eb61f5fa 100644
--- a/src/plugins/projectexplorer/project.cpp
+++ b/src/plugins/projectexplorer/project.cpp
@@ -376,7 +376,7 @@ void Project::setExtraProjectFiles(const QSet &projectDocumentPaths,
     const QSet toAdd = uniqueNewFiles - existingWatches;
     const QSet toRemove = existingWatches - uniqueNewFiles;
 
-    erase(d->m_extraProjectDocuments, [&toRemove](const std::unique_ptr &d) {
+    Utils::erase(d->m_extraProjectDocuments, [&toRemove](const std::unique_ptr &d) {
         return toRemove.contains(d->filePath());
     });
     if (docUpdater) {

From 80feee2b631f78a1a7fb5e33c94d8cd62c795f12 Mon Sep 17 00:00:00 2001
From: Mahmoud Badri 
Date: Tue, 19 Oct 2021 16:35:48 +0300
Subject: [PATCH 095/117] QmlDesigner: Distiguish between cancel and fail when
 importing assets

When asset importing fails we show a warning, but not when the user
cancels the importing.

Change-Id: I950d3b43c0f7c78a5abfb31a1974d2a9cd193522
Reviewed-by: Miikka Heikkinen 
---
 .../componentcore/designeractionmanager.cpp   |  4 +-
 .../componentcore/designeractionmanager.h     |  3 +-
 .../componentcore/modelnodeoperations.cpp     | 39 +++++++++----------
 .../componentcore/modelnodeoperations.h       | 11 ++++--
 .../itemlibraryassetimportdialog.cpp          |  5 ++-
 .../itemlibrary/itemlibraryview.cpp           |  8 ++--
 .../itemlibrary/itemlibrarywidget.cpp         |  8 +++-
 7 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index 8ca977e7428..d9a67a8400f 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -290,8 +290,8 @@ QHash DesignerActionManager::handleExternalAssetsDrop(cons
     for (const QString &category : categories) {
         AddResourceOperation operation = categoryOperation.value(category);
         QStringList files = categoryFiles.value(category);
-        bool success = operation(files, {});
-        if (success)
+        AddFilesResult result = operation(files, {});
+        if (result == AddFilesResult::Succeeded)
             addedCategoryFiles.insert(category, files);
     }
 
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
index 60e2c7562f9..e86e441b14d 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
@@ -28,6 +28,7 @@
 #include 
 #include "actioninterface.h"
 #include "modelnode.h"
+#include "modelnodeoperations.h"
 
 #include 
 #include 
@@ -45,7 +46,7 @@ namespace QmlDesigner {
 
 class DesignerActionManagerView;
 
-using AddResourceOperation = std::function;
+using AddResourceOperation = std::function;
 using ModelNodePreviewImageOperation = std::function;
 
 struct AddResourceHandler
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 10f1b4593d7..b4867404954 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -992,13 +992,15 @@ Utils::FilePath projectFilePath()
     return Utils::FilePath();
 }
 
-static bool addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory)
+static AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory)
 {
     QString directory = AddImagesDialog::getDirectory(fileNames, defaultDirectory);
     if (directory.isEmpty())
-        return true; // cancelling the dialog is considered success
+        return AddFilesResult::Cancelled;
+
+    DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
+    QTC_ASSERT(document, return AddFilesResult::Failed);
 
-    bool allSuccessful = true;
     QList> copyList;
     QStringList removeList;
     for (const QString &fileName : fileNames) {
@@ -1021,26 +1023,21 @@ static bool addFilesToProject(const QStringList &fileNames, const QString &defau
     // unnecessarily refreshing file models multiple times during the operation
     for (const auto &file : qAsConst(removeList))
         QFile::remove(file);
+
     for (const auto &filePair : qAsConst(copyList)) {
         const bool success = QFile::copy(filePair.first, filePair.second);
+        if (!success)
+            return AddFilesResult::Failed;
 
-        auto document = QmlDesignerPlugin::instance()->currentDesignDocument();
-
-        QTC_ASSERT(document, return false);
-
-        if (success) {
-            ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(document->fileName());
-            if (node) {
-                ProjectExplorer::FolderNode *containingFolder = node->parentFolderNode();
-                if (containingFolder)
-                    containingFolder->addFiles({Utils::FilePath::fromString(filePair.second)});
-            }
-        } else {
-            allSuccessful = false;
+        ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(document->fileName());
+        if (node) {
+            ProjectExplorer::FolderNode *containingFolder = node->parentFolderNode();
+            if (containingFolder)
+                containingFolder->addFiles({Utils::FilePath::fromString(filePair.second)});
         }
     }
 
-    return allSuccessful;
+    return AddFilesResult::Succeeded;
 }
 
 static QString getAssetDefaultDirectory(const QString &assetDir, const QString &defaultDirectory)
@@ -1060,22 +1057,22 @@ static QString getAssetDefaultDirectory(const QString &assetDir, const QString &
     return adjustedDefaultDirectory;
 }
 
-bool addFontToProject(const QStringList &fileNames, const QString &defaultDirectory)
+AddFilesResult addFontToProject(const QStringList &fileNames, const QString &defaultDirectory)
 {
     return addFilesToProject(fileNames, getAssetDefaultDirectory("fonts", defaultDirectory));
 }
 
-bool addSoundToProject(const QStringList &fileNames, const QString &defaultDirectory)
+AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &defaultDirectory)
 {
     return addFilesToProject(fileNames, getAssetDefaultDirectory("sounds", defaultDirectory));
 }
 
-bool addShaderToProject(const QStringList &fileNames, const QString &defaultDirectory)
+AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &defaultDirectory)
 {
     return addFilesToProject(fileNames, getAssetDefaultDirectory("shaders", defaultDirectory));
 }
 
-bool addImageToProject(const QStringList &fileNames, const QString &defaultDirectory)
+AddFilesResult addImageToProject(const QStringList &fileNames, const QString &defaultDirectory)
 {
     return addFilesToProject(fileNames, getAssetDefaultDirectory("images", defaultDirectory));
 }
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
index 0e302a3c65a..feb7faa556f 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
@@ -28,6 +28,9 @@
 #include "selectioncontext.h"
 
 namespace QmlDesigner {
+
+enum class AddFilesResult { Succeeded, Failed, Cancelled };
+
 namespace ModelNodeOperations {
 
 bool goIntoComponent(const ModelNode &modelNode);
@@ -73,10 +76,10 @@ void addItemToStackedContainer(const SelectionContext &selectionContext);
 void increaseIndexOfStackedContainer(const SelectionContext &selectionContext);
 void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext);
 void addTabBarToStackedContainer(const SelectionContext &selectionContext);
-bool addImageToProject(const QStringList &fileNames, const QString &directory);
-bool addFontToProject(const QStringList &fileNames, const QString &directory);
-bool addSoundToProject(const QStringList &fileNames, const QString &directory);
-bool addShaderToProject(const QStringList &fileNames, const QString &directory);
+AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory);
+AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory);
+AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory);
+AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &directory);
 void createFlowActionArea(const SelectionContext &selectionContext);
 void addTransition(const SelectionContext &selectionState);
 void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName);
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
index 04bc51284b9..135eaaf5aaf 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
@@ -788,7 +788,10 @@ void ItemLibraryAssetImportDialog::onClose()
         addInfo(tr("Canceling import."));
         m_importer.cancelImport();
     } else {
-        reject();
+        if (ui->progressBar->value() == 100) // import done successfully
+            accept();
+        else
+            reject();
         close();
         deleteLater();
     }
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
index 06b84d83f8b..9c8b4e09f90 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
@@ -245,13 +245,15 @@ void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap)
 
         m_importableExtensions3DMap = extMap;
 
-        auto import3DModelOperation = [this](const QStringList &fileNames, const QString &defaultDir) -> bool {
+        AddResourceOperation import3DModelOperation = [this](const QStringList &fileNames,
+                                                             const QString &defaultDir) -> AddFilesResult {
             auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir,
                                                               m_importableExtensions3DMap,
                                                               m_importOptions3DMap, {}, {},
                                                               Core::ICore::mainWindow());
-            importDlg->exec();
-            return true;
+            int result = importDlg->exec();
+
+            return result == QDialog::Accepted ? AddFilesResult::Succeeded : AddFilesResult::Cancelled;
         };
 
         auto add3DHandler = [&](const QString &group, const QString &ext) {
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index bd20722206e..ef1e85287a7 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
@@ -38,6 +38,7 @@
 #include 
 #include 
 #include "itemlibraryassetsiconprovider.h"
+#include "modelnodeoperations.h"
 #include 
 #include 
 #include 
@@ -621,8 +622,11 @@ void ItemLibraryWidget::addResources(const QStringList &files)
         QStringList fileNames = categoryFileNames.values(category);
         AddResourceOperation operation = categoryToOperation.value(category);
         QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category);
-        if (!operation(fileNames, document->fileName().parentDir().toString()))
-            Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), tr("Could not add %1 to project.").arg(fileNames.join(' ')));
+        AddFilesResult result = operation(fileNames, document->fileName().parentDir().toString());
+        if (result == AddFilesResult::Failed) {
+            Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
+                                                  tr("Could not add %1 to project.").arg(fileNames.join(' ')));
+        }
     }
 }
 

From 5de4743bb41d16a2319208b342801c5b521bc74d Mon Sep 17 00:00:00 2001
From: Mahmoud Badri 
Date: Fri, 15 Oct 2021 00:30:59 +0300
Subject: [PATCH 096/117] QmlDesigner: Persist horizontal component library's
 selected category

Moved showing and hiding categories logic to Cpp side so that:
- Currently selected category is persisted when the component library
  model is reset.
- QML side is clean of the mix of logic and UI.

Also reworked some logic/variables that are making the logic complex.

Task-number: QDS-5215
Change-Id: I8e9f5893f37a982283f1b1be9fee022f0b8afa32
Reviewed-by: Samuel Ghinet 
Reviewed-by: Miikka Heikkinen 
---
 .../itemLibraryQmlSources/ItemsView.qml       |  61 +-----
 .../itemlibrarycategoriesmodel.cpp            |  52 +++--
 .../itemlibrary/itemlibrarycategoriesmodel.h  |   9 +-
 .../itemlibrary/itemlibrarycategory.cpp       |   1 +
 .../itemlibrary/itemlibraryimport.cpp         |  52 +++--
 .../itemlibrary/itemlibraryimport.h           |  23 ++-
 .../itemlibrary/itemlibrarymodel.cpp          | 191 +++++++++++++-----
 .../components/itemlibrary/itemlibrarymodel.h |  34 +++-
 8 files changed, 261 insertions(+), 162 deletions(-)

diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
index de9d50f0429..815d4427ada 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
@@ -78,15 +78,10 @@ Item {
 
     property string importToRemove: ""
     property string importToAdd: ""
-    property var currentItem: null
     property var currentCategory: null
     property var currentImport: null
     property bool isHorizontalView: false
 
-    // horizontal component lib variables
-    property var selectedCategory: null
-    property var selectedCategoryImport: null
-
     // called from C++ to close context menu on focus out
     function closeContextMenu()
     {
@@ -94,21 +89,6 @@ Item {
         itemContextMenu.close()
     }
 
-    function showImportCategories()
-    {
-        if (itemLibraryModel.isAllCategoriesHidden()) {
-            itemsView.currentImport.importCatVisibleState = true
-            if (!itemLibraryModel.getIsAnyCategoryHidden())
-                itemLibraryModel.isAnyCategoryHidden = false
-
-            itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory()
-        }
-
-        itemsView.currentImport.importCatVisibleState = true
-        if (!itemLibraryModel.getIsAnyCategoryHidden())
-            itemLibraryModel.isAnyCategoryHidden = false
-    }
-
     onWidthChanged: {
         itemsView.isHorizontalView = itemsView.width > widthLimit
     }
@@ -135,10 +115,7 @@ Item {
                 visible: itemsView.currentCategory === null
                 height: visible ? implicitHeight : 0
                 enabled: itemsView.importToRemove !== ""
-                onTriggered: {
-                    showImportCategories()
-                    rootView.removeImport(itemsView.importToRemove)
-                }
+                onTriggered: rootView.removeImport(itemsView.importToRemove)
             }
 
             StudioControls.MenuSeparator {
@@ -169,12 +146,8 @@ Item {
                 text: qsTr("Hide Category")
                 visible: itemsView.currentCategory
                 height: visible ? implicitHeight : 0
-                onTriggered: {
-                    itemLibraryModel.isAnyCategoryHidden = true
-                    itemsView.currentCategory.categoryVisible = false
-                    itemsView.currentCategory.categorySelected = false
-                    itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory()
-                }
+                onTriggered: itemLibraryModel.hideCategory(itemsView.currentImport.importUrl,
+                                                           itemsView.currentCategory.categoryName)
             }
 
             StudioControls.MenuSeparator {
@@ -184,23 +157,14 @@ Item {
 
             StudioControls.MenuItem {
                 text: qsTr("Show Module Hidden Categories")
-                enabled: itemsView.currentImport && !itemsView.currentImport.importCatVisibleState
-                onTriggered: showImportCategories()
+                enabled: itemsView.currentImport && !itemsView.currentImport.allCategoriesVisible
+                onTriggered: itemLibraryModel.showImportHiddenCategories(itemsView.currentImport.importUrl)
             }
 
             StudioControls.MenuItem {
                 text: qsTr("Show All Hidden Categories")
                 enabled: itemLibraryModel.isAnyCategoryHidden
-                onTriggered: {
-                    if (itemLibraryModel.isAllCategoriesHidden()) {
-                        itemLibraryModel.showHiddenCategories()
-                        itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory()
-                        itemLibraryModel.isAnyCategoryHidden = false
-                    }
-
-                    itemLibraryModel.isAnyCategoryHidden = false
-                    itemLibraryModel.showHiddenCategories()
-                }
+                onTriggered: itemLibraryModel.showAllHiddenCategories()
             }
         }
 
@@ -419,8 +383,6 @@ Item {
 
                                             onClicked: (mouse) => {
                                                 itemLibraryModel.selectImportCategory(parent.parent.currentImportModel.importUrl, model.index)
-                                                itemsView.selectedCategory = model
-                                                itemsView.selectedCategoryImport = parent.parent.currentImportModel
 
                                                 if (mouse.button === Qt.RightButton && !rootView.isSearchActive() && categoryModel.rowCount() !== 1) {
                                                     itemsView.currentCategory = model
@@ -428,13 +390,6 @@ Item {
                                                     moduleContextMenu.popup()
                                                 }
                                             }
-                                            Component.onCompleted: {
-                                                if (categorySelected)
-                                                    categorySelected = !categorySelected
-                                                itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory()
-                                                if (itemsView.selectedCategory === categorySelected)
-                                                    itemsView.selectedCategoryImport = itemsView.selectedCategory.parent.currentImportModel
-                                            }
                                         }
                                     }
                                 }
@@ -473,10 +428,10 @@ Item {
                     rowSpacing: 7
 
                     Repeater {
-                        model: itemsView.selectedCategory ? itemsView.selectedCategory.itemModel : null
+                        model: itemLibraryModel.itemsModel
                         delegate: ItemDelegate {
                             visible: itemVisible
-                            textColor: itemsView.selectedCategoryImport && itemsView.selectedCategoryImport.importUnimported
+                            textColor: itemLibraryModel.importUnimportedSelected
                                        ? StudioTheme.Values.themeUnimportedModuleColor : StudioTheme.Values.themeTextColor
                             width: styleConstants.cellWidth + hItemGrid.flexibleWidth
                             height: styleConstants.cellHeight
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp
index d351232e36b..4962f5d6b4c 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp
@@ -147,20 +147,19 @@ void ItemLibraryCategoriesModel::resetModel()
 bool ItemLibraryCategoriesModel::isAllCategoriesHidden() const
 {
     for (const auto &category : std::as_const(m_categoryList)) {
-        // ignore "All Other Components" as its categoryVisible is always true
-        if (category->isCategoryVisible() && category->categoryName() != "All Other Components")
+        if (category->isCategoryVisible())
             return false;
     }
 
     return true;
 }
 
-void ItemLibraryCategoriesModel::showAllCategories(bool show)
+void ItemLibraryCategoriesModel::showAllCategories()
 {
     for (const auto &category : std::as_const(m_categoryList)) {
-        if (category->isCategoryVisible() != show) {
-            category->setCategoryVisible(show);
-            ItemLibraryModel::saveCategoryVisibleState(show, category->categoryName(),
+        if (!category->isCategoryVisible()) {
+            category->setCategoryVisible(true);
+            ItemLibraryModel::saveCategoryVisibleState(true, category->categoryName(),
                                                        category->ownerImport()->importName());
         }
     }
@@ -168,37 +167,56 @@ void ItemLibraryCategoriesModel::showAllCategories(bool show)
     emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categoryVisible")});
 }
 
-QObject *ItemLibraryCategoriesModel::selectFirstVisibleCategory()
+void ItemLibraryCategoriesModel::hideCategory(const QString &categoryName)
+{
+    for (int i = 0; i < m_categoryList.size(); ++i) {
+        const auto category = m_categoryList.at(i);
+        if (category->categoryName() == categoryName) {
+            category->setCategoryVisible(false);
+            ItemLibraryModel::saveCategoryVisibleState(false, category->categoryName(),
+                                                       category->ownerImport()->importName());
+            emit dataChanged(index(i), index(i), {m_roleNames.key("categoryVisible")});
+            break;
+        }
+    }
+}
+
+int ItemLibraryCategoriesModel::selectFirstVisibleCategory()
 {
     for (int i = 0; i < m_categoryList.length(); ++i) {
         const auto category = m_categoryList.at(i);
 
         if (category->isCategoryVisible()) {
             category->setCategorySelected(true);
-            emit dataChanged(index(i),index(i), {m_roleNames.key("categorySelected")});
-            return category;
+            emit dataChanged(index(i), index(i), {m_roleNames.key("categorySelected")});
+            return i;
         }
     }
 
-    return nullptr;
+    return -1;
 }
 
-void ItemLibraryCategoriesModel::clearSelectedCategories()
+void ItemLibraryCategoriesModel::clearSelectedCategory(int categoryIndex)
 {
-    for (const auto &category : std::as_const(m_categoryList))
-        category->setCategorySelected(false);
+    if (categoryIndex == -1 || m_categoryList.isEmpty())
+        return;
 
-    emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categorySelected")});
+    m_categoryList.at(categoryIndex)->setCategorySelected(false);
+    emit dataChanged(index(categoryIndex), index(categoryIndex), {m_roleNames.key("categorySelected")});
 }
 
-void ItemLibraryCategoriesModel::selectCategory(int categoryIndex)
+QPointer ItemLibraryCategoriesModel::selectCategory(int categoryIndex)
 {
-    const auto category = m_categoryList.at(categoryIndex);
+    if (categoryIndex == -1 || m_categoryList.isEmpty())
+        return nullptr;
+
+    const QPointer category = m_categoryList.at(categoryIndex);
     if (!category->categorySelected()) {
-        clearSelectedCategories();
         category->setCategorySelected(true);
         emit dataChanged(index(categoryIndex),index(categoryIndex), {m_roleNames.key("categorySelected")});
     }
+
+    return category;
 }
 
 void ItemLibraryCategoriesModel::addRoleNames()
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h
index 9433af804f9..36437a0ed66 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h
@@ -55,10 +55,11 @@ public:
     bool isAllCategoriesHidden() const;
     void sortCategorySections();
     void resetModel();
-    void showAllCategories(bool show = true);
-    void clearSelectedCategories();
-    QObject *selectFirstVisibleCategory();
-    void selectCategory(int categoryIndex);
+    void showAllCategories();
+    void hideCategory(const QString &categoryName);
+    void clearSelectedCategory(int categoryIndex);
+    int selectFirstVisibleCategory();
+    QPointer selectCategory(int categoryIndex);
 
 private:
     void addRoleNames();
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp
index 0744b7b2b3f..ce04b298fee 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp
@@ -137,6 +137,7 @@ void ItemLibraryCategory::setExpanded(bool expanded)
 void ItemLibraryCategory::setCategorySelected(bool selected)
 {
     m_categorySelected = selected;
+    emit categorySelectedChanged();
 }
 
 } // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp
index 7e696e43ef4..ebf13d0fe57 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp
@@ -133,28 +133,38 @@ bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool
     return hasVisibleCategories;
 }
 
-void ItemLibraryImport::showAllCategories(bool show)
+void ItemLibraryImport::showAllCategories()
 {
-    m_categoryModel.showAllCategories(show);
+    m_categoryModel.showAllCategories();
+    setAllCategoriesVisible(true);
 }
 
-void ItemLibraryImport::selectCategory(int categoryIndex)
+void ItemLibraryImport::hideCategory(const QString &categoryName)
 {
-    m_categoryModel.selectCategory(categoryIndex);
+    m_categoryModel.hideCategory(categoryName);
+    setAllCategoriesVisible(false);
 }
 
-QObject *ItemLibraryImport::selectFirstVisibleCategory()
+ItemLibraryCategory *ItemLibraryImport::selectCategory(int categoryIndex)
+{
+    return m_categoryModel.selectCategory(categoryIndex);
+}
+
+int ItemLibraryImport::selectFirstVisibleCategory()
 {
     return m_categoryModel.selectFirstVisibleCategory();
 }
 
-void ItemLibraryImport::clearSelectedCategories()
+void ItemLibraryImport::clearSelectedCategory(int categoryIndex)
 {
-    m_categoryModel.clearSelectedCategories();
+    m_categoryModel.clearSelectedCategory(categoryIndex);
 }
 
 bool ItemLibraryImport::isAllCategoriesHidden() const
 {
+    if (!m_isVisible)
+        return true;
+
     return m_categoryModel.isAllCategoriesHidden();
 }
 
@@ -221,7 +231,7 @@ void ItemLibraryImport::setImportExpanded(bool expanded)
     }
 }
 
-ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &categoryName) const
+ItemLibraryCategory *ItemLibraryImport::getCategoryByName(const QString &categoryName) const
 {
     for (ItemLibraryCategory *catSec : std::as_const(m_categoryModel.categorySections())) {
         if (catSec->categoryName() == categoryName)
@@ -231,6 +241,16 @@ ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &catego
     return nullptr;
 }
 
+ItemLibraryCategory *ItemLibraryImport::getCategoryAt(int categoryIndex) const
+{
+    const QList> categories = m_categoryModel.categorySections();
+
+    if (categoryIndex != -1 && !categories.isEmpty())
+        return categories.at(categoryIndex);
+
+    return nullptr;
+}
+
 // static
 QString ItemLibraryImport::userComponentsTitle()
 {
@@ -264,22 +284,14 @@ void ItemLibraryImport::updateRemovable()
     }
 }
 
-// returns true if all categories are visible, otherwise false
-bool ItemLibraryImport::importCatVisibleState() const
+bool ItemLibraryImport::allCategoriesVisible() const
 {
-    if (m_categoryModel.rowCount() > 0) {
-        for (ItemLibraryCategory *cat : m_categoryModel.categorySections()) {
-            if (!cat->isCategoryVisible())
-                return false;
-        }
-    }
-
-    return true;
+    return m_allCategoriesVisible;
 }
 
-void ItemLibraryImport::setImportCatVisibleState(bool show)
+void ItemLibraryImport::setAllCategoriesVisible(bool visible)
 {
-    m_categoryModel.showAllCategories(show);
+    m_allCategoriesVisible = visible;
 }
 
 } // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h
index f5a1cd02791..89aaca8e025 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h
@@ -43,7 +43,7 @@ class ItemLibraryImport : public QObject
     Q_PROPERTY(bool importExpanded READ importExpanded WRITE setImportExpanded NOTIFY importExpandChanged FINAL)
     Q_PROPERTY(bool importRemovable READ importRemovable NOTIFY importRemovableChanged FINAL)
     Q_PROPERTY(bool importUnimported READ importUnimported FINAL)
-    Q_PROPERTY(bool importCatVisibleState READ importCatVisibleState WRITE setImportCatVisibleState NOTIFY importCatVisibleStateChanged FINAL)
+    Q_PROPERTY(bool allCategoriesVisible READ allCategoriesVisible WRITE setAllCategoriesVisible NOTIFY allCategoriesVisibleChanged FINAL)
     Q_PROPERTY(QObject *categoryModel READ categoryModel NOTIFY categoryModelChanged FINAL)
 
 public:
@@ -65,11 +65,12 @@ public:
     bool importVisible() const;
     bool importUsed() const;
     bool importRemovable() const;
-    bool importCatVisibleState() const;
+    bool allCategoriesVisible() const;
     bool hasCategories() const;
     bool hasSingleCategory() const;
     bool isAllCategoriesHidden() const;
-    ItemLibraryCategory *getCategorySection(const QString &categoryName) const;
+    ItemLibraryCategory *getCategoryByName(const QString &categoryName) const;
+    ItemLibraryCategory *getCategoryAt(int categoryIndex) const;
 
     void addCategory(ItemLibraryCategory *category);
     QObject *categoryModel();
@@ -78,12 +79,14 @@ public:
     void setImportUsed(bool importUsed);
     void sortCategorySections();
     void setImportExpanded(bool expanded = true);
-    void setImportCatVisibleState(bool show);
+    void setAllCategoriesVisible(bool visible);
     void expandCategories(bool expand = true);
-    void showAllCategories(bool show = true);
-    void selectCategory(int categoryIndex);
-    QObject *selectFirstVisibleCategory();
-    void clearSelectedCategories();
+    void showAllCategories();
+    void hideCategory(const QString &categoryName);
+    ItemLibraryCategory *selectCategory(int categoryIndex);
+    int selectFirstVisibleCategory();
+    void clearSelectedCategory(int categoryIndex);
+    bool importUnimported() const { return m_sectionType == SectionType::Unimported; }
 
     static QString userComponentsTitle();
     static QString quick3DAssetsTitle();
@@ -97,17 +100,17 @@ signals:
     void importUsedChanged();
     void importExpandChanged();
     void importRemovableChanged();
-    void importCatVisibleStateChanged();
+    void allCategoriesVisibleChanged();
 
 private:
     void updateRemovable();
-    bool importUnimported() const { return m_sectionType == SectionType::Unimported; }
 
     Import m_import;
     bool m_importExpanded = true;
     bool m_isVisible = true;
     bool m_importUsed = false;
     bool m_importRemovable = false;
+    bool m_allCategoriesVisible = true;
     SectionType m_sectionType = SectionType::Default;
     ItemLibraryCategoriesModel m_categoryModel;
 };
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
index ebef71f63f5..b571cc4981d 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
@@ -59,8 +59,8 @@ bool ItemLibraryModel::loadExpandedState(const QString §ionName)
     return expandedStateHash.value(sectionName, true);
 }
 
-void ItemLibraryModel::saveCategoryVisibleState(bool isVisible, const QString &categoryName, const
-                                                QString &importName)
+void ItemLibraryModel::saveCategoryVisibleState(bool isVisible, const QString &categoryName,
+                                                const QString &importName)
 {
     categoryVisibleStateHash.insert(categoryName + '_' + importName, isVisible);
 }
@@ -70,58 +70,61 @@ bool ItemLibraryModel::loadCategoryVisibleState(const QString &categoryName, con
     return categoryVisibleStateHash.value(categoryName + '_' + importName, true);
 }
 
-void ItemLibraryModel::showHiddenCategories()
+void ItemLibraryModel::selectImportCategory(const QString &importUrl, int categoryIndex)
 {
+    clearSelectedCategory();
+
+    m_selectedImportUrl = importUrl;
+    m_selectedCategoryIndex = categoryIndex;
+
+    updateSelection();
+}
+
+void ItemLibraryModel::clearSelectedCategory()
+{
+    if (m_selectedCategoryIndex != -1) {
+        ItemLibraryImport *selectedImport = importByUrl(m_selectedImportUrl);
+        if (selectedImport)
+            selectedImport->clearSelectedCategory(m_selectedCategoryIndex);
+    }
+}
+
+void ItemLibraryModel::selectImportFirstVisibleCategory()
+{
+    if (m_selectedCategoryIndex != -1) {
+        ItemLibraryImport *selectedImport = importByUrl(m_selectedImportUrl);
+        if (selectedImport) {
+            ItemLibraryCategory *selectedCategory = selectedImport->getCategoryAt(m_selectedCategoryIndex);
+            if (selectedCategory) {
+                bool isUnimported = selectedImport->sectionType() == ItemLibraryImport::SectionType::Unimported;
+                // unimported category is always visible so checking its Import visibility instead
+                bool isVisible = isUnimported ? selectedImport->importVisible()
+                                              : selectedCategory->isCategoryVisible();
+                if (isVisible)
+                    return; // there is already a selected visible category
+
+                clearSelectedCategory();
+            }
+        }
+    }
+
     for (const QPointer &import : std::as_const(m_importList)) {
-        if (import->hasCategories())
-            import->showAllCategories(true);
+        if (!import->isAllCategoriesHidden()) {
+            m_selectedImportUrl = import->importUrl();
+            m_selectedCategoryIndex = import->selectFirstVisibleCategory();
+
+            ItemLibraryCategory *selectedCategory = import->getCategoryAt(m_selectedCategoryIndex);
+            if (selectedCategory) {
+                setItemsModel(selectedCategory->itemModel());
+                setImportUnimportedSelected(import->importUnimported());
+                return;
+            }
+        }
     }
 
-    categoryVisibleStateHash.clear();
-}
-
-bool ItemLibraryModel::getIsAnyCategoryHidden() const
-{
-    for (const bool &catState : std::as_const(categoryVisibleStateHash)) {
-        if (!catState)
-            return true;
-    }
-
-    return false;
-}
-
-void ItemLibraryModel::selectImportCategory(const QString importUrl, int categoryIndex)
-{
-    ItemLibraryImport *selectedCategoryImport = importByUrl(importUrl);
-
-    for (int i = 0; i < m_importList.length(); ++i) {
-        const auto importToSelect = m_importList.at(i);
-
-        if (selectedCategoryImport == importToSelect)
-            importToSelect->selectCategory(categoryIndex);
-        else
-            importToSelect->clearSelectedCategories();
-    }
-}
-
-bool ItemLibraryModel::isAllCategoriesHidden() const
-{
-    for (int i = 0; i < m_importList.length(); ++i) {
-        if (!m_importList.at(i)->isAllCategoriesHidden())
-            return false;
-    }
-
-    return true;
-}
-
-QObject *ItemLibraryModel::selectImportFirstVisibleCategory()
-{
-    for (const QPointer &import : std::as_const(m_importList)) {
-        if (!import->isAllCategoriesHidden())
-            return import->selectFirstVisibleCategory();
-    }
-
-    return nullptr;
+    m_selectedImportUrl.clear();
+    m_selectedCategoryIndex = -1;
+    setItemsModel(nullptr);
 }
 
 bool ItemLibraryModel::isAnyCategoryHidden() const
@@ -137,6 +140,30 @@ void ItemLibraryModel::setIsAnyCategoryHidden(bool state)
     }
 }
 
+bool ItemLibraryModel::importUnimportedSelected() const
+{
+    return m_importUnimportedSelected;
+}
+
+void ItemLibraryModel::setImportUnimportedSelected(bool state)
+{
+    if (state != m_importUnimportedSelected) {
+        m_importUnimportedSelected = state;
+        emit importUnimportedSelectedChanged();
+    }
+}
+
+QObject *ItemLibraryModel::itemsModel() const
+{
+    return m_itemsModel;
+}
+
+void ItemLibraryModel::setItemsModel(QObject *model)
+{
+    m_itemsModel = model;
+    emit itemsModelChanged();
+}
+
 void ItemLibraryModel::expandAll()
 {
     int i = 0;
@@ -164,6 +191,46 @@ void ItemLibraryModel::collapseAll()
     }
 }
 
+void ItemLibraryModel::hideCategory(const QString &importUrl, const QString &categoryName)
+{
+    ItemLibraryImport *import = importByUrl(importUrl);
+    if (!import)
+        return;
+
+    import->hideCategory(categoryName);
+
+    selectImportFirstVisibleCategory();
+    setIsAnyCategoryHidden(true);
+}
+
+void ItemLibraryModel::showImportHiddenCategories(const QString &importUrl)
+{
+    ItemLibraryImport *targetImport = nullptr;
+    bool hiddenCatsExist = false;
+    for (const QPointer &import : std::as_const(m_importList)) {
+        if (import->importUrl() == importUrl)
+            targetImport = import;
+        else
+            hiddenCatsExist |= !import->allCategoriesVisible();
+    }
+
+    if (targetImport) {
+        targetImport->showAllCategories();
+        updateSelection(); // useful when all categories are hidden
+        setIsAnyCategoryHidden(hiddenCatsExist);
+    }
+}
+
+void ItemLibraryModel::showAllHiddenCategories()
+{
+    for (const QPointer &import : std::as_const(m_importList))
+        import->showAllCategories();
+
+    updateSelection(); // useful when all categories are hidden
+    setIsAnyCategoryHidden(false);
+    categoryVisibleStateHash.clear();
+}
+
 void ItemLibraryModel::setFlowMode(bool b)
 {
     m_flowMode = b;
@@ -242,6 +309,8 @@ void ItemLibraryModel::setSearchText(const QString &searchText)
 
         bool changed = false;
         updateVisibility(&changed);
+
+        selectImportFirstVisibleCategory();
     }
 }
 
@@ -411,7 +480,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
             }
 
             // get or create category section
-            ItemLibraryCategory *categorySection = importSection->getCategorySection(catName);
+            ItemLibraryCategory *categorySection = importSection->getCategoryByName(catName);
             if (!categorySection) {
                 categorySection = new ItemLibraryCategory(catName, importSection);
                 importSection->addCategory(categorySection);
@@ -428,8 +497,11 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
     }
 
     sortSections();
+
     bool changed = false;
     updateVisibility(&changed);
+
+    updateSelection();
     endResetModel();
 }
 
@@ -453,6 +525,23 @@ void ItemLibraryModel::clearSections()
     m_importList.clear();
 }
 
+void ItemLibraryModel::updateSelection()
+{
+    if (m_selectedCategoryIndex != -1) {
+        ItemLibraryImport *selectedImport = importByUrl(m_selectedImportUrl);
+        if (selectedImport) {
+            ItemLibraryCategory *selectedCategory = selectedImport->selectCategory(m_selectedCategoryIndex);
+            if (selectedCategory) {
+                setItemsModel(selectedCategory->itemModel());
+                setImportUnimportedSelected(selectedImport->importUnimported());
+                return;
+            }
+        }
+    }
+
+    selectImportFirstVisibleCategory();
+}
+
 void ItemLibraryModel::registerQmlTypes()
 {
     qmlRegisterAnonymousType("ItemLibraryModel", 1);
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
index ad9803821ff..7852999edd4 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
@@ -33,15 +33,19 @@ QT_FORWARD_DECLARE_CLASS(QMimeData)
 
 namespace QmlDesigner {
 
-class ItemLibraryInfo;
+class ItemLibraryCategory;
 class ItemLibraryEntry;
-class Model;
 class ItemLibraryImport;
+class ItemLibraryInfo;
+class Model;
 
 class ItemLibraryModel : public QAbstractListModel
 {
     Q_OBJECT
+
     Q_PROPERTY(bool isAnyCategoryHidden READ isAnyCategoryHidden WRITE setIsAnyCategoryHidden NOTIFY isAnyCategoryHiddenChanged FINAL)
+    Q_PROPERTY(QObject *itemsModel READ itemsModel WRITE setItemsModel NOTIFY itemsModelChanged)
+    Q_PROPERTY(bool importUnimportedSelected READ importUnimportedSelected WRITE setImportUnimportedSelected NOTIFY importUnimportedSelectedChanged)
 
 public:
     explicit ItemLibraryModel(QObject *parent = nullptr);
@@ -66,20 +70,26 @@ public:
     bool isAnyCategoryHidden() const;
     void setIsAnyCategoryHidden(bool state);
 
+    bool importUnimportedSelected() const;
+    void setImportUnimportedSelected(bool state);
+
+    QObject *itemsModel() const;
+    void setItemsModel(QObject *model);
+
     static void registerQmlTypes();
     static void saveExpandedState(bool expanded, const QString §ionName);
     static bool loadExpandedState(const QString §ionName);
     static void saveCategoryVisibleState(bool isVisible, const QString &categoryName, const QString
                                          &importName);
     static bool loadCategoryVisibleState(const QString &categoryName, const QString &importName);
+    void selectImportFirstVisibleCategory();
 
     Q_INVOKABLE void expandAll();
     Q_INVOKABLE void collapseAll();
-    Q_INVOKABLE void showHiddenCategories();
-    Q_INVOKABLE bool getIsAnyCategoryHidden() const;
-    Q_INVOKABLE void selectImportCategory(const QString importUrl, int categoryIndex);
-    Q_INVOKABLE QObject *selectImportFirstVisibleCategory();
-    Q_INVOKABLE bool isAllCategoriesHidden() const;
+    Q_INVOKABLE void hideCategory(const QString &importUrl, const QString &categoryName);
+    Q_INVOKABLE void showImportHiddenCategories(const QString &importUrl);
+    Q_INVOKABLE void showAllHiddenCategories();
+    Q_INVOKABLE void selectImportCategory(const QString &importUrl, int categoryIndex);
 
     Import entryToImport(const ItemLibraryEntry &entry);
 
@@ -87,12 +97,18 @@ public:
 
 signals:
     void isAnyCategoryHiddenChanged();
+    void importUnimportedSelectedChanged();
+    void selectedCategoryChanged();
+    void selectedImportUrlChanged();
+    void itemsModelChanged();
 
 private:
     void updateVisibility(bool *changed);
     void addRoleNames();
     void sortSections();
     void clearSections();
+    void updateSelection();
+    void clearSelectedCategory();
 
     QList> m_importList;
     QHash m_roleNames;
@@ -100,6 +116,10 @@ private:
     QString m_searchText;
     bool m_flowMode = false;
     bool m_isAnyCategoryHidden = false;
+    bool m_importUnimportedSelected = false;
+    QString m_selectedImportUrl;
+    int m_selectedCategoryIndex = -1;
+    QObject *m_itemsModel = nullptr; // items model for the horizontal layout
 
     inline static QHash expandedStateHash;
     inline static QHash categoryVisibleStateHash;

From 755932eca792011531a28c7bdae227ff2449c014 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Tue, 19 Oct 2021 18:15:28 +0200
Subject: [PATCH 097/117] CppEditor: Fix crash

Fixes: QTCREATORBUG-26441
Change-Id: Ib5a99d474eac8677a65eb8a4a9b4fbe259c61ad3
Reviewed-by: Orgad Shaneh 
---
 .../cppeditor/cppfollowsymbolundercursor.cpp    | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
index ac2747cad71..11a3a70be09 100644
--- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
+++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
@@ -417,17 +417,18 @@ bool maybeAppendArgumentOrParameterList(QString *expression, const QTextCursor &
 
 bool isCursorOnTrailingReturnType(const QList &astPath)
 {
-    for (auto it = astPath.cend() - 1, begin = astPath.cbegin(); it >= begin; --it) {
+    if (astPath.size() < 3)
+        return false;
+    for (auto it = astPath.cend() - 3, begin = astPath.cbegin(); it >= begin; --it) {
+        if (!(*it)->asTrailingReturnType())
+            continue;
         const auto nextIt = it + 1;
         const auto nextNextIt = nextIt + 1;
-        if (nextNextIt != astPath.cend() && (*it)->asTrailingReturnType()) {
-            return (*nextIt)->asNamedTypeSpecifier()
-                    && ((*nextNextIt)->asSimpleName()
-                        || (*nextNextIt)->asQualifiedName()
-                        || (*nextNextIt)->asTemplateId());
-        }
+        return (*nextIt)->asNamedTypeSpecifier()
+               && ((*nextNextIt)->asSimpleName()
+                   || (*nextNextIt)->asQualifiedName()
+                   || (*nextNextIt)->asTemplateId());
     }
-
     return false;
 }
 

From 93ae6f4c06775626db2b2527f7b0c550bf1ea8c4 Mon Sep 17 00:00:00 2001
From: Eike Ziller 
Date: Tue, 19 Oct 2021 10:55:45 +0200
Subject: [PATCH 098/117] Fix performance issue in Locator with Qt 6

Locator tries to de-duplicate entries in case results from multiple
filters are collected. This is done so we don't get e.g. multiple
results for file names, from the various file filters (open documents,
project files, included files, ...).

For this we define operator== and qHash for LocatorFilterEntry, and add
them to a set of "seen" items based on their "internalData" QVariant.

For string data that works fine. For non-string data we used qHash for
the variant's internal data, and that changed in Qt 6 so we get the same
hash a lot of times which hits on the performance big time.

Defining qHash generically for QVariant isn't really supported. Since
our use case is to de-duplicate items if the internal data is a string,
simply restrict our de-duplication to that explicitly.

Fixes: QTCREATORBUG-26415
Task-number: QTCREATORBUG-24098
Change-Id: Ifdad17e7e66e9fe4b1300de51c45a5efac73cf3a
Reviewed-by: David Schulz 
---
 .../coreplugin/locator/ilocatorfilter.h       |  9 ++-----
 .../coreplugin/locator/locatorsearchutils.cpp | 25 +++++++------------
 2 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h
index bc44cfb1f79..48679878691 100644
--- a/src/plugins/coreplugin/locator/ilocatorfilter.h
+++ b/src/plugins/coreplugin/locator/ilocatorfilter.h
@@ -31,9 +31,10 @@
 #include 
 #include 
 
-#include 
 #include 
 #include 
+#include 
+#include 
 
 namespace Core {
 
@@ -74,12 +75,6 @@ struct LocatorFilterEntry
         , displayIcon(icon)
     {}
 
-    bool operator==(const LocatorFilterEntry &other) const {
-        if (internalData.canConvert(QVariant::String))
-            return (internalData.toString() == other.internalData.toString());
-        return internalData.constData() == other.internalData.constData();
-    }
-
     /* backpointer to creating filter */
     ILocatorFilter *filter = nullptr;
     /* displayed string */
diff --git a/src/plugins/coreplugin/locator/locatorsearchutils.cpp b/src/plugins/coreplugin/locator/locatorsearchutils.cpp
index a9eb1a7de23..cefe9481c04 100644
--- a/src/plugins/coreplugin/locator/locatorsearchutils.cpp
+++ b/src/plugins/coreplugin/locator/locatorsearchutils.cpp
@@ -29,21 +29,10 @@
 #include 
 #include 
 
-namespace Core {
-
-uint qHash(const LocatorFilterEntry &entry)
-{
-    if (entry.internalData.canConvert(QVariant::String))
-        return QT_PREPEND_NAMESPACE(qHash)(entry.internalData.toString());
-    return QT_PREPEND_NAMESPACE(qHash)(entry.internalData.constData());
-}
-
-} // namespace Core
-
 void Core::Internal::runSearch(QFutureInterface &future,
                                const QList &filters, const QString &searchText)
 {
-    QSet alreadyAdded;
+    QSet alreadyAdded;
     const bool checkDuplicates = (filters.size() > 1);
     for (ILocatorFilter *filter : filters) {
         if (future.isCanceled())
@@ -53,11 +42,15 @@ void Core::Internal::runSearch(QFutureInterface &futur
         QVector uniqueFilterResults;
         uniqueFilterResults.reserve(filterResults.size());
         for (const LocatorFilterEntry &entry : filterResults) {
-            if (checkDuplicates && alreadyAdded.contains(entry))
-                continue;
+            if (checkDuplicates) {
+                const QString stringData = entry.internalData.toString();
+                if (!stringData.isEmpty()) {
+                    if (alreadyAdded.contains(stringData))
+                        continue;
+                    alreadyAdded.insert(stringData);
+                }
+            }
             uniqueFilterResults.append(entry);
-            if (checkDuplicates)
-                alreadyAdded.insert(entry);
         }
         if (!uniqueFilterResults.isEmpty())
             future.reportResults(uniqueFilterResults);

From 0e5d632e5b43fbf218b82d9bf6d694d1fbb82361 Mon Sep 17 00:00:00 2001
From: Eike Ziller 
Date: Tue, 19 Oct 2021 10:56:15 +0200
Subject: [PATCH 099/117] Move FilePath's hash methods to the right header

Change-Id: Ie3932daf381bc03f37ae67722dcddc5b2e4823e5
Reviewed-by: Qt CI Bot 
Reviewed-by: David Schulz 
---
 src/libs/utils/filepath.h  | 15 +++++++++++++++
 src/libs/utils/fileutils.h | 11 -----------
 2 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h
index 21ef3e12438..474f2c1416c 100644
--- a/src/libs/utils/filepath.h
+++ b/src/libs/utils/filepath.h
@@ -201,6 +201,11 @@ private:
 
 using FilePaths = QList;
 
+inline uint qHash(const Utils::FilePath &a, uint seed = 0)
+{
+    return a.hash(seed);
+}
+
 } // namespace Utils
 
 QT_BEGIN_NAMESPACE
@@ -208,3 +213,13 @@ QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug dbg, const Utils::FilePath &c);
 QT_END_NAMESPACE
 
 Q_DECLARE_METATYPE(Utils::FilePath)
+
+namespace std {
+template<>
+struct QTCREATOR_UTILS_EXPORT hash
+{
+    using argument_type = Utils::FilePath;
+    using result_type = size_t;
+    result_type operator()(const argument_type &fn) const;
+};
+} // namespace std
diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h
index 9fd0b6c2a03..c87ca5d5dd0 100644
--- a/src/libs/utils/fileutils.h
+++ b/src/libs/utils/fileutils.h
@@ -316,16 +316,5 @@ private:
 
 QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FilePath &fn);
 
-inline uint qHash(const Utils::FilePath &a, uint seed = 0) { return a.hash(seed); }
-
 } // namespace Utils
 
-namespace std {
-template<> struct QTCREATOR_UTILS_EXPORT hash
-{
-    using argument_type = Utils::FilePath;
-    using result_type = size_t;
-    result_type operator()(const argument_type &fn) const;
-};
-} // namespace std
-

From a95ee64feda9d7f138c7983d4b8d9e78cfca27a8 Mon Sep 17 00:00:00 2001
From: David Schulz 
Date: Wed, 20 Oct 2021 06:36:31 +0200
Subject: [PATCH 100/117] Editor: Fix build for Qt < 5.15.2

Change-Id: I06d1ec50159f3370fde05633de8e14f599140369
Reviewed-by: Eike Ziller 
---
 src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
index 3e1160b0db3..f4e88b719a7 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
@@ -728,7 +728,11 @@ MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &ca
     /**
      * match the pattern
      */
+#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
+    const auto result = regexp.match(text.toString(), offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+#else
     const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+#endif
     if (result.capturedStart() == offset) {
         /**
          * we only need to compute the captured texts if we have real capture groups

From ac2906cd6029e98f226ff3f2fd6573426449c6b7 Mon Sep 17 00:00:00 2001
From: Leena Miettinen 
Date: Thu, 7 Oct 2021 12:14:17 +0200
Subject: [PATCH 101/117] Doc: Update info about available project wizard
 templates

The Qt Quick Application wizard template was simplified.

Change-Id: I716d8d03aa508b6f8204b028c5e11691e1e469c3
Reviewed-by: Alessandro Portale 
---
 .../creator-projects-creating.qdoc            | 19 +----
 .../src/python/creator-python-project.qdocinc |  6 +-
 .../creator-only/qtquick-creating.qdoc        | 71 ++++++-------------
 ...uick-tutorial-create-empty-project.qdocinc |  7 +-
 4 files changed, 31 insertions(+), 72 deletions(-)

diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc
index d997de4a3dd..34eeb024b05 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc
@@ -89,7 +89,7 @@
     files, as defined by the wizard.
 
     For example, if you choose to create a Qt Quick application, \QC generates a
-    QML file that you can modify in the Design mode.
+    QML file that you can modify in the \uicontrol Edit mode.
 
     \section1 Selecting Project Type
 
@@ -108,7 +108,7 @@
                 you can deploy, run, and debug on MCU boards. For more
                 information, see \l {Connecting MCUs}.
         \row
-            \li {1,2} Application (Qt)
+            \li {1,3} Application (Qt)
             \li Qt Widgets Application
             \li Uses \QD forms to design a Qt widget based user interface for
                 the desktop and C++ to implement the application logic.
@@ -116,23 +116,10 @@
             \li Qt Console Application
             \li Uses a single main.cpp file.
         \row
-            \li {1,4} Application (Qt Quick)
-            \li Qt Quick Application - Empty
+            \li Qt Quick Application
             \li Creates a Qt Quick 2 application project that can contain both
                 QML and C++ code. You can build the application and deploy it
                 to desktop, embedded, and mobile target platforms.
-        \row
-            \li Qt Quick Application - Scroll
-            \li Uses the \l{ScrollView} component to implement a scrollable
-                list view (requires Qt 5.9 or later).
-        \row
-            \li Qt Quick Application - Stack
-            \li Uses the \l{StackView} component to implement a set of pages
-                with a stack-based navigation model (requires Qt 5.7 or later).
-        \row
-           \li Qt Quick Application - Swipe
-           \li Uses the \l{SwipeView} component to implement a set of pages
-                with a swipe-based navigation model (requires Qt 5.7 or later).
         \row
             \li {1,4} Application (Qt for Python)
             \li Qt for Python - Empty
diff --git a/doc/qtcreator/src/python/creator-python-project.qdocinc b/doc/qtcreator/src/python/creator-python-project.qdocinc
index 7dc7ee67379..7543434e065 100644
--- a/doc/qtcreator/src/python/creator-python-project.qdocinc
+++ b/doc/qtcreator/src/python/creator-python-project.qdocinc
@@ -119,7 +119,8 @@
     select \uicontrol {REPL Import File}. To also import all functions from
     the file, select \uicontrol {REPL Import *}.
 
-    Open the .ui file in the Design mode to create a widget-based UI in \QD.
+    Open the .ui file in the \uicontrol Design mode to create a widget-based UI
+    in \QD.
 
     The \uicontrol Window wizard adds similar code to the source file, without
     the UI bits.
@@ -188,7 +189,8 @@
     sys.exit(app.exec_())
     \endcode
 
-    Open the .qml file in the Design mode to design a Qt Quick UI in \QMLD.
+    Open the .qml file in the \uicontrol Edit mode to design a Qt Quick UI, or
+    use \QDS.
 
 //! [python qml project wizards]
 */
diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc b/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc
index 56c481dd7c5..b69f1dc22db 100644
--- a/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc
+++ b/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc
@@ -32,7 +32,7 @@
 /*!
     \previouspage creator-visual-editor.html
     \page quick-projects.html
-    \nextpage creator-using-qt-quick-designer.html
+    \nextpage quick-converting-ui-projects.html
 
     \title Creating Qt Quick Projects
 
@@ -47,23 +47,11 @@
             \li Wizard Template
             \li Purpose
         \row
-            \li {1,4} Application (Qt Quick)
-            \li Qt Quick Application - Empty
+            \li Application (Qt)
+            \li Qt Quick Application
             \li Creates a Qt Quick 2 application project that can contain both
                 QML and C++ code. You can build the application and deploy it
                 to desktop, embedded, and mobile target platforms.
-        \row
-            \li Qt Quick Application - Scroll
-            \li Uses the \l{ScrollView} component to implement a scrollable
-                list view (requires Qt 5.9 or later).
-        \row
-            \li Qt Quick Application - Stack
-            \li Uses the \l{StackView} component to implement a set of pages
-                with a stack-based navigation model (requires Qt 5.7 or later).
-        \row
-           \li Qt Quick Application - Swipe
-           \li Uses the \l{SwipeView} component to implement a set of pages
-                with a swipe-based navigation model (requires Qt 5.7 or later).
         \row
             \li Application (Qt for Python)
             \li Qt for Python - Qt Quick Application
@@ -72,14 +60,13 @@
         \row
             \li Other Project
             \li Qt Quick UI Prototype
-            \li Creates a \l{Creating Qt Quick UI Projects}{Qt Quick UI project}
-                with a single QML file that contains the main view. You can
-                preview Qt Quick 2 UI projects in the
-                \l{Validating with Target Hardware}{QML Scene preview tool}.
-                You do not need to build them, because they do not contain any
-                C++ code.
+            \li Creates a Qt Quick UI project with a single QML file that
+                contains the main view. You can preview Qt Quick 2 UI projects
+                in the QML Scene preview tool. You do not need to build them,
+                because they do not contain any C++ code.
 
-                Use this template only if you are prototyping. You cannot create
+                This project type is compatible with \QDS. However, use this
+                template only if you are prototyping. You cannot create
                 a full application by using this template.
 
                 Qt Quick UI projects cannot be deployed to embedded or mobile
@@ -104,24 +91,17 @@
     \list 1
 
         \li Select \uicontrol File > \uicontrol {New File or Project} >
-            \uicontrol {Application (Qt Quick)}.
+            \uicontrol {Application (Qt)} > \uicontrol {Qt Quick Application}
+            > \uicontrol Choose.
 
-        \li Select the application type:
-            \list
-                \li \uicontrol {Qt Quick Application - Empty}
-                \li \uicontrol {Qt Quick Application - Scroll}
-                \li \uicontrol {Qt Quick Application - Stack}
-                \li \uicontrol {Qt Quick Application - Swipe}
-            \endlist
-
-        \li Select \uicontrol Choose to open the \uicontrol {Project Location}
-            dialog.
-
-        \li In the \uicontrol Name field, enter a name for the application.
+        \li In the \uicontrol {Project Location} dialog, \uicontrol Name field,
+            enter a name for the project. Keep in mind that you cannot easily
+            change the project name later.
 
         \li In the \uicontrol {Create in} field, enter the path for the project
             files. Select the \uicontrol {Use as default project location} check
-            box to create new projects in this folder by default.
+            box to create new projects in this folder by default. You can move
+            project folders later without problems.
 
         \li Select \uicontrol Next (or \uicontrol Continue on \macos) to open
             the \uicontrol {Define Build System} dialog.
@@ -143,9 +123,8 @@
 
             \note If you have not installed the Qt Virtual Keyboard module when
             you installed Qt, an error message will appear when you try to open
-            the \e main.qml in the \uicontrol {Form Editor} in the Design mode.
-            You can use the \l {Installing Qt}{Qt Maintenance Tool} to install
-            Qt Virtual Keyboard.
+            \e main.qml for editing. You can use the \l {Installing Qt}
+            {Qt Maintenance Tool} to install Qt Virtual Keyboard.
 
         \li Select \uicontrol Next to open the \uicontrol {Translation File}
             dialog.
@@ -179,14 +158,8 @@
 
     \endlist
 
-    For the Empty and Scroll applications, \QC creates a QML file,
-    \e main.qml, that you can modify in the \uicontrol {Form Editor}
-    or the \uicontrol {Text Editor}.
-
-    For the Stack and Swipe applications, \QC generates two \l{UI Files}{UI files},
-    \e Page1Form.ui.qml and \e Page2Form.ui.qml, that you can modify in the
-    \uicontrol {Form Editor} and a QML file, \e main.qml, that you can
-    modify in the \uicontrol {Text Editor} to add the application logic.
+    \QC creates a QML file, \e main.qml, that you can modify in the
+    \uicontrol Edit mode.
 
     \include creator-python-project.qdocinc python qml project wizards
 
@@ -240,9 +213,7 @@
 
             \note If you have not installed the Qt Virtual Keyboard module when
             you installed Qt, an error message will appear when you try to open
-            the \e main.qml in the \uicontrol {Form Editor} in the Design mode.
-            You can use the \l {Installing Qt}{Qt Maintenance Tool} to install
-            Qt Virtual Keyboard.
+            \e main.qml.
 
         \li Select \uicontrol Next to open the \uicontrol {Kit Selection}
             dialog.
diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-tutorial-create-empty-project.qdocinc b/doc/qtcreator/src/qtquick/creator-only/qtquick-tutorial-create-empty-project.qdocinc
index 48ddb0569ac..fad9db2bab4 100644
--- a/doc/qtcreator/src/qtquick/creator-only/qtquick-tutorial-create-empty-project.qdocinc
+++ b/doc/qtcreator/src/qtquick/creator-only/qtquick-tutorial-create-empty-project.qdocinc
@@ -31,8 +31,7 @@
     \list 1
 
         \li Select \uicontrol File > \uicontrol {New File or Project} >
-            \uicontrol {Application (Qt Quick)} >
-            \uicontrol {Qt Quick Application - Empty}.
+            \uicontrol {Application (Qt)} > \uicontrol {Qt Quick Application}.
 
         \li Select \uicontrol Choose to open the
             \uicontrol {Project Location} dialog.
@@ -82,8 +81,8 @@
 
     \endlist
 
-    For more information about the settings that you skipped, see
-    \l{Creating Qt Quick Applications}.
+    For more information about the settings that you skipped and the other
+    templates available, see \l{Creating Qt Quick Applications}.
 
 //! [qtquick empty application]
 */

From 575ca89b3e2a48a3cabedfec55f32e21fdb2f18d Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Tue, 19 Oct 2021 15:00:19 +0200
Subject: [PATCH 102/117] CppEditor: Do not save clangd file path in settings

... if it is the default value.

Change-Id: I5efde72abe5a1979144352d09d461642f936224a
Reviewed-by: David Schulz 
---
 src/plugins/cppeditor/cppcodemodelsettings.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp
index 1a7cf1255f8..66c07bed7a1 100644
--- a/src/plugins/cppeditor/cppcodemodelsettings.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp
@@ -402,7 +402,8 @@ QVariantMap ClangdSettings::Data::toMap() const
 {
     QVariantMap map;
     map.insert(useClangdKey(), useClangd);
-    map.insert(clangdPathKey(), executableFilePath.toString());
+    if (executableFilePath != fallbackClangdFilePath())
+        map.insert(clangdPathKey(), executableFilePath.toString());
     map.insert(clangdIndexingKey(), enableIndexing);
     map.insert(clangdThreadLimitKey(), workerThreadLimit);
     map.insert(clangdDocumentThresholdKey(), documentUpdateThreshold);

From 71e6e30dbf9dbeaaeeeec10d8d0887fd8d8ead08 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Tue, 19 Oct 2021 14:17:01 +0200
Subject: [PATCH 103/117] ProjectExplorer: Fix expansion of variables in
 working directory

... when actually running the binary.
Amends 3dd8831f14.

Fixes: QTCREATORBUG-26438
Change-Id: I69fb8df514cb3ab00df76e241a3e367031fce94b
Reviewed-by: Eike Ziller 
---
 src/plugins/projectexplorer/runconfigurationaspects.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp
index 0a3a2634b0f..2291a86fbda 100644
--- a/src/plugins/projectexplorer/runconfigurationaspects.cpp
+++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp
@@ -251,7 +251,9 @@ FilePath WorkingDirectoryAspect::workingDirectory() const
     const Environment env = m_envAspect ? m_envAspect->environment()
                                         : Environment::systemEnvironment();
     FilePath res = m_workingDirectory;
-    const QString workingDir = m_workingDirectory.path();
+    QString workingDir = m_workingDirectory.path();
+    if (m_macroExpander)
+        workingDir = m_macroExpander->expandProcessArgs(workingDir);
     res.setPath(PathChooser::expandedDirectory(workingDir, env, QString()));
     return res;
 }

From 19119b953395257bac345486a3ab10b9c5cf16c5 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Fri, 15 Oct 2021 16:24:25 +0200
Subject: [PATCH 104/117] ClangCodeModel: Use more suitable location for
 compile_commands.json

... for clangd.
Putting it in the build directory seems sensible in principle, but that
can be problematic for in-source builds. So introduce another level of
nesting to prevent conflicts.

Fixes: QTCREATORBUG-26431
Change-Id: Id66aa0852d206695f2fc2ec42292b1cecefe2b59
Reviewed-by: David Schulz 
---
 src/plugins/clangcodemodel/clangcodemodelplugin.cpp |  2 +-
 .../clangcodemodel/clangmodelmanagersupport.cpp     |  4 ++--
 src/plugins/clangcodemodel/clangutils.cpp           | 13 +++++--------
 src/plugins/clangcodemodel/clangutils.h             |  4 ++--
 4 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
index a6ead8c3fe2..3a13c4542db 100644
--- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
+++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
@@ -82,7 +82,7 @@ void ClangCodeModelPlugin::generateCompilationDB()
 
     QFuture task
             = QtConcurrent::run(&Internal::generateCompilationDB, projectInfo,
-                                CompilationDbPurpose::Project,
+                                projectInfo->buildRoot(), CompilationDbPurpose::Project,
                                 warningsConfigForProject(target->project()),
                                 optionsForProject(target->project()));
     Core::ProgressManager::addTask(task, tr("Generating Compilation DB"), "generate compilation db");
diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
index 5be1f2c83cd..d1c6b0d0ce3 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
@@ -286,7 +286,7 @@ void ClangModelManagerSupport::updateLanguageClient(
         if (const ProjectExplorer::Target * const target = project->activeTarget()) {
             if (const ProjectExplorer::BuildConfiguration * const bc
                     = target->activeBuildConfiguration()) {
-                return bc->buildDirectory();
+                return bc->buildDirectory() / ".qtc_clangd";
             }
         }
         return Utils::FilePath();
@@ -363,7 +363,7 @@ void ClangModelManagerSupport::updateLanguageClient(
         });
 
     });
-    auto future = Utils::runAsync(&Internal::generateCompilationDB, projectInfo,
+    auto future = Utils::runAsync(&Internal::generateCompilationDB, projectInfo, jsonDbDir,
                                   CompilationDbPurpose::CodeModel,
                                   warningsConfigForProject(project),
                                   optionsForProject(project));
diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp
index bbe9817380e..a089248d039 100644
--- a/src/plugins/clangcodemodel/clangutils.cpp
+++ b/src/plugins/clangcodemodel/clangutils.cpp
@@ -372,18 +372,15 @@ static QJsonObject createFileObject(const FilePath &buildDir,
 }
 
 GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo::ConstPtr projectInfo,
+                                                  const Utils::FilePath &baseDir,
                                                   CompilationDbPurpose purpose,
                                                   const ClangDiagnosticConfig &warningsConfig,
                                                   const QStringList &projectOptions)
 {
-    const FilePath buildDir = projectInfo->buildRoot();
-    QTC_ASSERT(!buildDir.isEmpty(), return GenerateCompilationDbResult(QString(),
+    QTC_ASSERT(!baseDir.isEmpty(), return GenerateCompilationDbResult(QString(),
         QCoreApplication::translate("ClangUtils", "Could not retrieve build directory.")));
-
-    QDir dir(buildDir.toString());
-    if (!dir.exists())
-        dir.mkpath(dir.path());
-    QFile compileCommandsFile(buildDir.toString() + "/compile_commands.json");
+    QTC_CHECK(baseDir.ensureWritableDir());
+    QFile compileCommandsFile(baseDir.toString() + "/compile_commands.json");
     const bool fileOpened = compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
     if (!fileOpened) {
         return GenerateCompilationDbResult(QString(),
@@ -397,7 +394,7 @@ GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo::
         if (purpose == CompilationDbPurpose::Project)
             args = projectPartArguments(*projectPart);
         for (const ProjectFile &projFile : projectPart->files) {
-            const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile,
+            const QJsonObject json = createFileObject(baseDir, args, *projectPart, projFile,
                                                       purpose, warningsConfig, projectOptions);
             if (compileCommandsFile.size() > 1)
                 compileCommandsFile.write(",");
diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h
index 1d46e6a49b0..c3a496f7797 100644
--- a/src/plugins/clangcodemodel/clangutils.h
+++ b/src/plugins/clangcodemodel/clangutils.h
@@ -88,8 +88,8 @@ public:
 
 enum class CompilationDbPurpose { Project, CodeModel };
 GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo::ConstPtr projectInfo,
-            CompilationDbPurpose purpose, const CppEditor::ClangDiagnosticConfig &warningsConfig,
-            const QStringList &projectOptions);
+        const Utils::FilePath &baseDir, CompilationDbPurpose purpose,
+        const CppEditor::ClangDiagnosticConfig &warningsConfig, const QStringList &projectOptions);
 
 class DiagnosticTextInfo
 {

From 181a2927fe256dc73fa383b716697485d913c3b2 Mon Sep 17 00:00:00 2001
From: David Schulz 
Date: Wed, 20 Oct 2021 11:14:11 +0200
Subject: [PATCH 105/117] Editor: fix unindent

Fixes: QTCREATORBUG-26412
Change-Id: I9743d3ff10b89318270eee43899da6c2baccad20
Reviewed-by: Orgad Shaneh 
---
 src/plugins/texteditor/texteditor.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index d7643af772c..1d236b497fb 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -1966,7 +1966,7 @@ void TextEditorWidget::indent()
 
 void TextEditorWidget::unindent()
 {
-    setMultiTextCursor(textDocument()->indent(multiTextCursor()));
+    setMultiTextCursor(textDocument()->unindent(multiTextCursor()));
 }
 
 void TextEditorWidget::undo()

From ae0b648a853d5e4687f2f9d71c902856dcb3d42b Mon Sep 17 00:00:00 2001
From: Eike Ziller 
Date: Wed, 20 Oct 2021 11:38:26 +0200
Subject: [PATCH 106/117] CMake build: Allow compilation without QtQuick

Disable the parts that require it in that case.

Change-Id: I3f62eb9b325905ea225009aad6b9020cef545da6
Reviewed-by: Cristian Adam 
---
 CMakeLists.txt                           | 5 ++---
 src/CMakeLists.txt                       | 3 ++-
 src/libs/tracing/CMakeLists.txt          | 2 +-
 src/plugins/qmldesigner/CMakeLists.txt   | 1 +
 src/plugins/studiowelcome/CMakeLists.txt | 1 +
 src/tools/qml2puppet/CMakeLists.txt      | 1 +
 6 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 162b0a9aeee..87be55233dd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,8 +49,7 @@ endif()
 
 find_package(Qt5
   ${IDE_QT_VERSION_MIN}
-  COMPONENTS Concurrent Core Gui Network PrintSupport Qml Quick
-    QuickWidgets Sql Widgets Xml Core5Compat ${QT_TEST_COMPONENT}
+  COMPONENTS Concurrent Core Gui Network PrintSupport Qml Sql Widgets Xml Core5Compat ${QT_TEST_COMPONENT}
   REQUIRED
 )
 if (Qt5_VERSION VERSION_LESS 6.0.0)
@@ -66,7 +65,7 @@ else()
   set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml_modules")
 endif()
 find_package(Qt5 COMPONENTS LinguistTools QUIET)
-find_package(Qt5 COMPONENTS Designer DesignerComponents Help SerialPort Svg Tools QUIET)
+find_package(Qt5 COMPONENTS Quick QuickWidgets Designer DesignerComponents Help SerialPort Svg Tools QUIET)
 
 option(BUILD_WITH_PCH "Build with precompiled headers" ON)
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 799d8ef68c9..70dfa9b5f6e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -51,8 +51,9 @@ endif()
 
 include(CMakeFindDependencyMacro)
 find_dependency(Qt5 ${IDE_QT_VERSION_MIN}
-  COMPONENTS Concurrent Core Gui Widgets Core5Compat Network PrintSupport Qml Quick QuickWidgets Sql REQUIRED
+  COMPONENTS Concurrent Core Gui Widgets Core5Compat Network PrintSupport Qml Sql REQUIRED
 )
+find_dependency(Qt5 COMPONENTS Quick QuickWidgets QUIET)
 
 if (NOT IDE_VERSION)
   include(\${CMAKE_CURRENT_LIST_DIR}/QtCreatorIDEBranding.cmake)
diff --git a/src/libs/tracing/CMakeLists.txt b/src/libs/tracing/CMakeLists.txt
index 9378c0e4e02..c34f583810f 100644
--- a/src/libs/tracing/CMakeLists.txt
+++ b/src/libs/tracing/CMakeLists.txt
@@ -46,7 +46,7 @@ else() # < Qt 6.2
   find_package(Qt6 COMPONENTS ShaderTools QUIET)
 
   add_qtc_library(Tracing
-    CONDITION TARGET Qt6::ShaderTools
+    CONDITION TARGET Qt6::ShaderTools AND TARGET Qt5::Quick
     FEATURE_INFO
     DEPENDS Utils Qt5::Qml Qt5::Quick
     PUBLIC_DEPENDS Qt5::Widgets
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index cee0c2e369f..0fe3867a7ef 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -4,6 +4,7 @@ if (APPLE)
 endif()
 
 add_qtc_plugin(QmlDesigner
+  CONDITION TARGET Qt5::QuickWidgets
   DEPENDS
     QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
     Qt5::QuickWidgets Qt5::CorePrivate Sqlite
diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt
index d22625e7c75..2ae3bdcc9a0 100644
--- a/src/plugins/studiowelcome/CMakeLists.txt
+++ b/src/plugins/studiowelcome/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_qtc_plugin(StudioWelcome
+  CONDITION TARGET Qt5::QuickWidgets
   DEPENDS Qt5::QuickWidgets
   PLUGIN_DEPENDS Core ProjectExplorer QtSupport
   DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/"
diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt
index 924e3a838c1..4606ee57082 100644
--- a/src/tools/qml2puppet/CMakeLists.txt
+++ b/src/tools/qml2puppet/CMakeLists.txt
@@ -97,6 +97,7 @@ extend_qtc_library(qml2puppet_static
 )
 
 add_qtc_executable(qml2puppet
+  CONDITION TARGET Qt5::QuickPrivate
   DEPENDS
     Qt5::CorePrivate Qt5::Widgets Qt5::QmlPrivate
     Qt5::QuickPrivate Qt5::Network Qt5::GuiPrivate

From 2948d282ce6518d1befd3e1d3371089a9863cac8 Mon Sep 17 00:00:00 2001
From: Jarek Kobus 
Date: Thu, 14 Oct 2021 10:27:45 +0200
Subject: [PATCH 107/117] Don't call DocumentManager::addDocument() from
 non-main thread

Detect that constructor of ResourceTopLevelNode is being
run from non-main thread and omit creation of ResourceFileWatcher
in this case. The construction of ResourceFileWatcher
will be postponed until the node tree returns back
to the main thread. This happens later inside
Project::setRootProjectNode() when ProjectTree::applyTreeManager()
is called for the second time - this time it's done from the main
thread. In order to setup the lacking resource file watchers
we install an additional folder node visitor only in case when
the handler is called from main thread. The visitor
sets up the lacking resource watchers if that's still needed.

Amends: 0bcab32657f1511892eda53194dce259e40edf21

Fixes: QTCREATORBUG-26417
Change-Id: Ia1bfb7f284afb833b6b4291accc4d0a91bd0d6c5
Reviewed-by: Eike Ziller 
---
 src/libs/utils/CMakeLists.txt                 |  1 +
 src/libs/utils/threadutils.cpp                | 38 ++++++++++++++++
 src/libs/utils/threadutils.h                  | 35 +++++++++++++++
 src/libs/utils/utils-lib.pri                  |  2 +
 src/libs/utils/utils.qbs                      |  2 +
 .../fileapidataextractor.cpp                  |  2 +-
 src/plugins/coreplugin/documentmanager.cpp    |  3 ++
 src/plugins/projectexplorer/project.cpp       |  3 +-
 src/plugins/projectexplorer/projecttree.cpp   |  4 +-
 src/plugins/projectexplorer/projecttree.h     |  9 +++-
 src/plugins/projectexplorer/treescanner.cpp   |  2 +-
 .../qbsprojectmanager/qbsnodetreebuilder.cpp  |  2 +-
 .../resourceeditor/resourceeditorplugin.cpp   | 43 ++++++++++++-------
 src/plugins/resourceeditor/resourcenode.cpp   | 16 +++++--
 src/plugins/resourceeditor/resourcenode.h     |  1 +
 15 files changed, 136 insertions(+), 27 deletions(-)
 create mode 100644 src/libs/utils/threadutils.cpp
 create mode 100644 src/libs/utils/threadutils.h

diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt
index 9db6ea5f1e7..b94b2b42227 100644
--- a/src/libs/utils/CMakeLists.txt
+++ b/src/libs/utils/CMakeLists.txt
@@ -168,6 +168,7 @@ add_qtc_library(Utils
     textfileformat.cpp textfileformat.h
     textutils.cpp textutils.h
     theme/theme.cpp theme/theme.h theme/theme_p.h
+    threadutils.cpp threadutils.h
     tooltip/effects.h
     tooltip/tips.cpp tooltip/tips.h
     tooltip/tooltip.cpp tooltip/tooltip.h
diff --git a/src/libs/utils/threadutils.cpp b/src/libs/utils/threadutils.cpp
new file mode 100644
index 00000000000..7d10199c4ab
--- /dev/null
+++ b/src/libs/utils/threadutils.cpp
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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 "threadutils.h"
+
+#include 
+#include 
+
+namespace Utils {
+
+bool isMainThread()
+{
+    return QThread::currentThread() == qApp->thread();
+}
+
+} // namespace Utils
diff --git a/src/libs/utils/threadutils.h b/src/libs/utils/threadutils.h
new file mode 100644
index 00000000000..cc59658c277
--- /dev/null
+++ b/src/libs/utils/threadutils.h
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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 "utils_global.h"
+
+namespace Utils {
+
+QTCREATOR_UTILS_EXPORT bool isMainThread();
+
+} // namespace Utils
+
diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri
index ddaae4bb697..a8280ba3267 100644
--- a/src/libs/utils/utils-lib.pri
+++ b/src/libs/utils/utils-lib.pri
@@ -143,6 +143,7 @@ SOURCES += \
     $$PWD/link.cpp \
     $$PWD/linecolumn.cpp \
     $$PWD/multitextcursor.cpp \
+    $$PWD/threadutils.cpp \
     $$PWD/singleton.cpp
 
 HEADERS += \
@@ -310,6 +311,7 @@ HEADERS += \
     $$PWD/launchersocket.h \
     $$PWD/qtcsettings.h \
     $$PWD/multitextcursor.h \
+    $$PWD/threadutils.h \
     $$PWD/singleton.h
 
 FORMS += $$PWD/filewizardpage.ui \
diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs
index 77f80dd81b8..6d888f87ac4 100644
--- a/src/libs/utils/utils.qbs
+++ b/src/libs/utils/utils.qbs
@@ -298,6 +298,8 @@ Project {
             "textfileformat.h",
             "textutils.cpp",
             "textutils.h",
+            "threadutils.cpp",
+            "threadutils.h",
             "treemodel.cpp",
             "treemodel.h",
             "treeviewcombobox.cpp",
diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
index 7200a060002..d5836605f48 100644
--- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
+++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
@@ -757,7 +757,7 @@ FileApiQtcData extractData(FileApiData &input,
     result.projectParts = generateRawProjectParts(data, sourceDirectory, buildDirectory);
 
     auto rootProjectNode = generateRootProjectNode(data, sourceDirectory, buildDirectory);
-    ProjectTree::applyTreeManager(rootProjectNode.get()); // QRC nodes
+    ProjectTree::applyTreeManager(rootProjectNode.get(), ProjectTree::AsyncPhase); // QRC nodes
     result.rootProjectNode = std::move(rootProjectNode);
 
     setupLocationInfoForTargets(result.rootProjectNode.get(), result.buildTargets);
diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp
index d7d5f17d8f1..4fd4213dbbb 100644
--- a/src/plugins/coreplugin/documentmanager.cpp
+++ b/src/plugins/coreplugin/documentmanager.cpp
@@ -55,6 +55,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -326,6 +327,7 @@ static void addFileInfo(IDocument *document, const FilePath &filePath, const Fil
    (The added file names are guaranteed to be absolute and cleaned.) */
 static void addFileInfos(const QList &documents)
 {
+    QTC_ASSERT(isMainThread(), return);
     FilePaths pathsToWatch;
     FilePaths linkPathsToWatch;
     for (IDocument *document : documents) {
@@ -400,6 +402,7 @@ void DocumentManager::addDocuments(const QList &documents, bool add
 */
 static void removeFileInfo(IDocument *document)
 {
+    QTC_ASSERT(isMainThread(), return);
     if (!d->m_documentsWithWatch.contains(document))
         return;
     foreach (const FilePath &filePath, d->m_documentsWithWatch.value(document)) {
diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
index 620eb61f5fa..38cdf161713 100644
--- a/src/plugins/projectexplorer/project.cpp
+++ b/src/plugins/projectexplorer/project.cpp
@@ -586,7 +586,8 @@ void Project::setRootProjectNode(std::unique_ptr &&root)
     }
 
     if (root) {
-        ProjectTree::applyTreeManager(root.get());
+        ProjectTree::applyTreeManager(root.get(), ProjectTree::AsyncPhase);
+        ProjectTree::applyTreeManager(root.get(), ProjectTree::FinalPhase);
         root->setParentFolderNode(d->m_containerNode.get());
     }
 
diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp
index aa8e79f9efb..ee040d5a37f 100644
--- a/src/plugins/projectexplorer/projecttree.cpp
+++ b/src/plugins/projectexplorer/projecttree.cpp
@@ -402,13 +402,13 @@ void ProjectTree::registerTreeManager(const TreeManagerFunction &treeChange)
         s_instance->m_treeManagers.append(treeChange);
 }
 
-void ProjectTree::applyTreeManager(FolderNode *folder)
+void ProjectTree::applyTreeManager(FolderNode *folder, ConstructionPhase phase)
 {
     if (!folder)
         return;
 
     for (TreeManagerFunction &f : s_instance->m_treeManagers)
-        f(folder);
+        f(folder, phase);
 }
 
 bool ProjectTree::hasNode(const Node *node)
diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h
index 060dad22903..3947666d3a6 100644
--- a/src/plugins/projectexplorer/projecttree.h
+++ b/src/plugins/projectexplorer/projecttree.h
@@ -68,6 +68,11 @@ public:
         const bool m_active = false;
     };
 
+    enum ConstructionPhase {
+        AsyncPhase,
+        FinalPhase
+    };
+
     // Integration with ProjectTreeWidget
     static void registerWidget(Internal::ProjectTreeWidget *widget);
     static void unregisterWidget(Internal::ProjectTreeWidget *widget);
@@ -79,9 +84,9 @@ public:
 
     static void highlightProject(Project *project, const QString &message);
 
-    using TreeManagerFunction = std::function;
+    using TreeManagerFunction = std::function;
     static void registerTreeManager(const TreeManagerFunction &treeChange);
-    static void applyTreeManager(FolderNode *folder);
+    static void applyTreeManager(FolderNode *folder, ConstructionPhase phase);
 
     // Nodes:
     static bool hasNode(const Node *node);
diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp
index ce6da40b1c2..88e7b8d4a83 100644
--- a/src/plugins/projectexplorer/treescanner.cpp
+++ b/src/plugins/projectexplorer/treescanner.cpp
@@ -159,7 +159,7 @@ static std::unique_ptr createFolderNode(const Utils::FilePath &direc
         std::unique_ptr node(fn->clone());
         fileSystemNode->addNestedNode(std::move(node));
     }
-    ProjectTree::applyTreeManager(fileSystemNode.get()); // QRC nodes
+    ProjectTree::applyTreeManager(fileSystemNode.get(), ProjectTree::AsyncPhase); // QRC nodes
     return fileSystemNode;
 }
 
diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp
index c481975753f..7e3c31c378a 100644
--- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp
+++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp
@@ -232,7 +232,7 @@ QbsProjectNode *QbsNodeTreeBuilder::buildTree(const QString &projectName,
     }
     buildSystemFiles->compress();
     root->addNode(std::move(buildSystemFiles));
-    ProjectTree::applyTreeManager(root.get()); // QRC nodes
+    ProjectTree::applyTreeManager(root.get(), ProjectTree::AsyncPhase); // QRC nodes
     return root.release();
 }
 
diff --git a/src/plugins/resourceeditor/resourceeditorplugin.cpp b/src/plugins/resourceeditor/resourceeditorplugin.cpp
index 62a4d752456..f901a417dff 100644
--- a/src/plugins/resourceeditor/resourceeditorplugin.cpp
+++ b/src/plugins/resourceeditor/resourceeditorplugin.cpp
@@ -46,6 +46,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -247,21 +248,33 @@ ResourceEditorPluginPrivate::ResourceEditorPluginPrivate(ResourceEditorPlugin *q
 
 void ResourceEditorPlugin::extensionsInitialized()
 {
-    ProjectTree::registerTreeManager([](FolderNode *folder) {
-        QList toReplace;
-        folder->forEachNode([&toReplace](FileNode *fn) {
-            if (fn->fileType() == FileType::Resource)
-                toReplace.append(fn);
-        });
-
-        for (FileNode *file : qAsConst(toReplace)) {
-            FolderNode *const pn = file->parentFolderNode();
-            QTC_ASSERT(pn, continue);
-            const Utils::FilePath path = file->filePath();
-            auto topLevel = std::make_unique(path, pn->filePath());
-            topLevel->setEnabled(file->isEnabled());
-            topLevel->setIsGenerated(file->isGenerated());
-            pn->replaceSubtree(file, std::move(topLevel));
+    ProjectTree::registerTreeManager([](FolderNode *folder, ProjectTree::ConstructionPhase phase) {
+        switch (phase) {
+        case ProjectTree::AsyncPhase: {
+            QList toReplace;
+            folder->forEachNode([&toReplace](FileNode *fn) {
+                if (fn->fileType() == FileType::Resource)
+                    toReplace.append(fn);
+            });
+            for (FileNode *file : qAsConst(toReplace)) {
+                FolderNode *const pn = file->parentFolderNode();
+                QTC_ASSERT(pn, continue);
+                const Utils::FilePath path = file->filePath();
+                auto topLevel = std::make_unique(path, pn->filePath());
+                topLevel->setEnabled(file->isEnabled());
+                topLevel->setIsGenerated(file->isGenerated());
+                pn->replaceSubtree(file, std::move(topLevel));
+            }
+            break;
+        }
+        case ProjectTree::FinalPhase: {
+            folder->forEachNode({}, [](FolderNode *fn) {
+                auto *topLevel = dynamic_cast(fn);
+                if (topLevel)
+                    topLevel->setupWatcherIfNeeded();
+            });
+            break;
+        }
         }
     });
 }
diff --git a/src/plugins/resourceeditor/resourcenode.cpp b/src/plugins/resourceeditor/resourcenode.cpp
index 30be6b0c0a3..75f35da4d8a 100644
--- a/src/plugins/resourceeditor/resourcenode.cpp
+++ b/src/plugins/resourceeditor/resourcenode.cpp
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -251,10 +252,8 @@ ResourceTopLevelNode::ResourceTopLevelNode(const FilePath &filePath,
     setShowWhenEmpty(true);
 
     if (!filePath.isEmpty()) {
-        if (filePath.isReadableFile()) {
-            m_document = new ResourceFileWatcher(this);
-            DocumentManager::addDocument(m_document);
-        }
+        if (filePath.isReadableFile())
+            setupWatcherIfNeeded();
     } else {
         m_contents = contents;
     }
@@ -267,6 +266,15 @@ ResourceTopLevelNode::ResourceTopLevelNode(const FilePath &filePath,
     addInternalNodes();
 }
 
+void ResourceTopLevelNode::setupWatcherIfNeeded()
+{
+    if (m_document || !isMainThread())
+        return;
+
+    m_document = new ResourceFileWatcher(this);
+    DocumentManager::addDocument(m_document);
+}
+
 ResourceTopLevelNode::~ResourceTopLevelNode()
 {
     if (m_document)
diff --git a/src/plugins/resourceeditor/resourcenode.h b/src/plugins/resourceeditor/resourcenode.h
index a992e267dc8..03ae8039f0c 100644
--- a/src/plugins/resourceeditor/resourcenode.h
+++ b/src/plugins/resourceeditor/resourcenode.h
@@ -39,6 +39,7 @@ public:
                          const QString &contents = {});
     ~ResourceTopLevelNode() override;
 
+    void setupWatcherIfNeeded();
     void addInternalNodes();
 
     bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override;

From ac96f0fa061b4e47173d490a339565caa94238c1 Mon Sep 17 00:00:00 2001
From: Jarek Kobus 
Date: Wed, 20 Oct 2021 12:13:37 +0200
Subject: [PATCH 108/117] Don't expand qrc items recursively

This fixes the recursive expansion of e.g.
"qtbase/tests/auto/corelib/io/qfile/copy-fallback.qrc"
which includes itself.

Change-Id: Ib345a2d6de4fa2eefd76eed58b99a72fcb8c84b5
Reviewed-by: Eike Ziller 
---
 src/plugins/resourceeditor/resourceeditorplugin.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/plugins/resourceeditor/resourceeditorplugin.cpp b/src/plugins/resourceeditor/resourceeditorplugin.cpp
index f901a417dff..36de99ca394 100644
--- a/src/plugins/resourceeditor/resourceeditorplugin.cpp
+++ b/src/plugins/resourceeditor/resourceeditorplugin.cpp
@@ -255,6 +255,8 @@ void ResourceEditorPlugin::extensionsInitialized()
             folder->forEachNode([&toReplace](FileNode *fn) {
                 if (fn->fileType() == FileType::Resource)
                     toReplace.append(fn);
+            }, {}, [](const FolderNode *fn) {
+                return dynamic_cast(fn) == nullptr;
             });
             for (FileNode *file : qAsConst(toReplace)) {
                 FolderNode *const pn = file->parentFolderNode();

From c292a4d591e403461c241bf900ba2250cbe71edb Mon Sep 17 00:00:00 2001
From: Jarek Kobus 
Date: Wed, 20 Oct 2021 14:37:18 +0200
Subject: [PATCH 109/117] Update qlitehtml submodule to incorporate the fix for
 broken shortcuts

The same happens in Creator.

Fixes: QTBUG-97189
Change-Id: Ib1e47176108d51ba6e7395cd7dfe0ab0325ea294
Reviewed-by: Eike Ziller 
---
 src/libs/qlitehtml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml
index 2fbaad08a01..e6fcc8ddb4e 160000
--- a/src/libs/qlitehtml
+++ b/src/libs/qlitehtml
@@ -1 +1 @@
-Subproject commit 2fbaad08a01d611858bef5e747addea7f42318b3
+Subproject commit e6fcc8ddb4e435160cca6a94bd7b011fd1698656

From 15639d00edf5cdc26d8ef2c784219af95ec6b6c5 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Wed, 20 Oct 2021 14:42:25 +0200
Subject: [PATCH 110/117] ProjectExplorer: Prevent cascading "Replacement for"
 kit names

Fixes: QTCREATORBUG-26330
Change-Id: Id7abd00afb70fe2d2e3c1a43e2ea1298c0ff20cc
Reviewed-by: David Schulz 
---
 src/plugins/projectexplorer/project.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
index 38cdf161713..b283862c467 100644
--- a/src/plugins/projectexplorer/project.cpp
+++ b/src/plugins/projectexplorer/project.cpp
@@ -805,8 +805,9 @@ void Project::createTargetFromMap(const QVariantMap &map, int index)
             deviceTypeId = Constants::DESKTOP_DEVICE_TYPE;
         const QString formerKitName = targetMap.value(Target::displayNameKey()).toString();
         k = KitManager::registerKit([deviceTypeId, &formerKitName](Kit *kit) {
-                const QString tempKitName = makeUniquelyNumbered(
-                            tr("Replacement for \"%1\"").arg(formerKitName),
+                const QString kitNameSuggestion = formerKitName.contains(tr("Replacement for"))
+                        ? formerKitName : tr("Replacement for \"%1\"").arg(formerKitName);
+                const QString tempKitName = makeUniquelyNumbered(kitNameSuggestion,
                         transform(KitManager::kits(), &Kit::unexpandedDisplayName));
                 kit->setUnexpandedDisplayName(tempKitName);
                 DeviceTypeKitAspect::setDeviceTypeId(kit, deviceTypeId);

From 11c73adbe04c51b0cc3f52b4e057d5a83f203708 Mon Sep 17 00:00:00 2001
From: Leena Miettinen 
Date: Wed, 20 Oct 2021 15:15:35 +0200
Subject: [PATCH 111/117] Doc: Remove obsolete files

References to these files have been removed, but the files
were forgotten.

Change-Id: I412d5daf2acf07b4f8c00715bc01e4422bbc1179
Reviewed-by: Johanna Vanhatapio 
---
 doc/qtcreator/images/qml-export-gimp.png        | Bin 96879 -> 0 bytes
 .../images/qml-observer-context-menu.png        | Bin 44145 -> 0 bytes
 .../images/qtcreator-iso-icon-browser.png       | Bin 23508 -> 0 bytes
 3 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 doc/qtcreator/images/qml-export-gimp.png
 delete mode 100644 doc/qtcreator/images/qml-observer-context-menu.png
 delete mode 100644 doc/qtcreator/images/qtcreator-iso-icon-browser.png

diff --git a/doc/qtcreator/images/qml-export-gimp.png b/doc/qtcreator/images/qml-export-gimp.png
deleted file mode 100644
index 5c78a4013bba66e53574715c499c03903e78a97c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 96879
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

+FQ~ow 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 bktuirm&xXXytfz_7#KWV{an^LB{Ts57KN}} diff --git a/doc/qtcreator/images/qml-observer-context-menu.png b/doc/qtcreator/images/qml-observer-context-menu.png deleted file mode 100644 index c7d35b0db3876545dac28d04a1a0d1af545956a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44145 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 diff --git a/doc/qtcreator/images/qtcreator-iso-icon-browser.png b/doc/qtcreator/images/qtcreator-iso-icon-browser.png deleted file mode 100644 index b59b319b1b1d654e3a11ecb0f1535b287cb00b4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23508 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 E0PKk>I{*Lx From 3871e40f432c9a0d7cb072acba17273f113ccd59 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 14 Oct 2021 22:27:08 +0300 Subject: [PATCH 112/117] Fix qHash-related size compatibility warnings by MSVC Change-Id: I3b7981ce78b67db4b996f99682284a0b911d8cd7 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../qml2puppet/instances/servernodeinstance.cpp | 2 +- .../qml2puppet/instances/servernodeinstance.h | 11 +++++++++-- .../src/indexer/katehighlightingindexer.cpp | 4 ++-- src/libs/cplusplus/LookupContext.cpp | 5 +++-- src/libs/cplusplus/LookupItem.cpp | 6 +++--- src/libs/cplusplus/LookupItem.h | 3 ++- src/libs/extensionsystem/pluginspec.cpp | 2 +- src/libs/extensionsystem/pluginspec.h | 4 +++- src/libs/modelinglib/qmt/infrastructure/handle.h | 2 +- .../modelinglib/qmt/style/defaultstyleengine.cpp | 15 ++++++++------- src/libs/modelinglib/qmt/style/objectvisuals.cpp | 2 +- src/libs/modelinglib/qmt/style/objectvisuals.h | 4 +++- src/libs/qmljs/qmljsdialect.cpp | 4 ++-- src/libs/qmljs/qmljsdialect.h | 3 ++- src/libs/qmljs/qmljsimportdependencies.cpp | 4 ++-- src/libs/qmljs/qmljsimportdependencies.h | 3 ++- src/libs/qmljs/qmljsinterpreter.cpp | 2 +- src/libs/qmljs/qmljsinterpreter.h | 3 ++- src/libs/qmljs/qmljslink.cpp | 5 +++-- src/libs/utils/filepath.cpp | 2 +- src/libs/utils/filepath.h | 5 +++-- src/libs/utils/id.cpp | 2 +- src/libs/utils/id.h | 3 ++- src/libs/utils/link.cpp | 2 +- src/libs/utils/link.h | 5 +++-- src/plugins/clangtools/clangtoolsdiagnostic.cpp | 2 +- src/plugins/clangtools/clangtoolsdiagnostic.h | 4 +++- .../cmakeprojectmanager/cmakeconfigitem.cpp | 2 +- src/plugins/cmakeprojectmanager/cmakeconfigitem.h | 3 ++- .../cmakeprojectmanager/fileapidataextractor.h | 2 +- src/plugins/cppcheck/cppcheckdiagnostic.cpp | 2 +- src/plugins/cppcheck/cppcheckdiagnostic.h | 3 ++- src/plugins/fakevim/fakevimhandler.cpp | 2 +- src/plugins/ios/iosprobe.cpp | 4 ++-- src/plugins/ios/iosprobe.h | 7 +++++-- src/plugins/modeleditor/modelindexer.cpp | 5 +++-- src/plugins/modeleditor/modelindexer.h | 4 +++- src/plugins/projectexplorer/buildtargetinfo.h | 3 ++- src/plugins/projectexplorer/deployablefile.cpp | 2 +- src/plugins/projectexplorer/deployablefile.h | 3 ++- src/plugins/projectexplorer/expanddata.cpp | 2 +- src/plugins/projectexplorer/expanddata.h | 4 +++- src/plugins/projectexplorer/task.cpp | 2 +- src/plugins/projectexplorer/task.h | 11 ++++++----- .../qmakeprojectmanager/qmakeparsernodes.cpp | 4 ++-- .../qmakeprojectmanager/qmakeparsernodes.h | 5 +++-- .../qmldesigner/designercore/include/import.h | 4 +++- .../qmldesigner/designercore/model/import.cpp | 2 +- .../qmlprofiler/qmlprofilertraceclient.cpp | 2 +- src/plugins/remotelinux/deploymenttimeinfo.cpp | 2 +- .../codeassist/genericproposalmodel.cpp | 2 +- src/plugins/texteditor/fontsettings.cpp | 4 ++-- src/plugins/texteditor/texteditor.cpp | 2 +- src/plugins/texteditor/texteditor.h | 3 ++- src/shared/proparser/proitems.cpp | 2 +- src/shared/proparser/proitems.h | 4 ++-- src/shared/proparser/qmakeevaluator.cpp | 2 +- src/shared/proparser/qmakeglobals.h | 3 ++- 58 files changed, 126 insertions(+), 85 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index fc5118727b4..97b5031260c 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -517,7 +517,7 @@ QDebug operator <<(QDebug debug, const ServerNodeInstance &instance) return debug.space(); } -uint qHash(const ServerNodeInstance &instance) +ServerNodeInstance::QHashValueType qHash(const ServerNodeInstance &instance) { return ::qHash(instance.instanceId()); } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h index 52ead77e125..7fd6453daa5 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h @@ -67,6 +67,13 @@ namespace Internal { class ServerNodeInstance { +public: +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +using QHashValueType = uint; +#else +using QHashValueType = size_t; +#endif + friend class NodeInstanceServer; friend class Qt4NodeInstanceServer; friend class Qt4PreviewNodeInstanceServer; @@ -76,7 +83,7 @@ class ServerNodeInstance friend class Qt5CapturePreviewNodeInstanceServer; friend class Qt5TestNodeInstanceServer; friend class QHash; - friend uint qHash(const ServerNodeInstance &instance); + friend QHashValueType qHash(const ServerNodeInstance &instance); friend bool operator==(const ServerNodeInstance &first, const ServerNodeInstance &second); friend QDebug operator<<(QDebug debug, const ServerNodeInstance &instance); friend class NodeMetaInfo; @@ -220,7 +227,7 @@ private: // variables QSharedPointer m_nodeInstance; }; -uint qHash(const ServerNodeInstance &instance); +ServerNodeInstance::QHashValueType qHash(const ServerNodeInstance &instance); bool operator ==(const ServerNodeInstance &first, const ServerNodeInstance &second); bool operator <(const ServerNodeInstance &first, const ServerNodeInstance &second); QDebug operator <<(QDebug debug, const ServerNodeInstance &instance); diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp index 789089625b8..4de51ba7c89 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp @@ -350,7 +350,7 @@ private: friend uint qHash(const Item &item, uint seed = 0) { - return qHash(item.content, seed); + return uint(qHash(item.content, seed)); } friend bool operator==(const Item &item0, const Item &item1) @@ -719,7 +719,7 @@ private: friend uint qHash(const Style &style, uint seed = 0) { - return qHash(style.name, seed); + return uint(qHash(style.name, seed)); } friend bool operator==(const Style &style0, const Style &style1) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 5eaa04baf4c..3f7e791115c 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -150,9 +151,9 @@ bool operator==(const FullyQualifiedName &left, const FullyQualifiedName &right) return compareFullyQualifiedName(left.fqn, right.fqn); } -uint qHash(const FullyQualifiedName &fullyQualifiedName) +Utils::QHashValueType qHash(const FullyQualifiedName &fullyQualifiedName) { - uint h = 0; + Utils::QHashValueType h = 0; for (int i = 0; i < fullyQualifiedName.fqn.size(); ++i) { if (const Name *n = fullyQualifiedName.fqn.at(i)) { if (const Identifier *id = n->identifier()) { diff --git a/src/libs/cplusplus/LookupItem.cpp b/src/libs/cplusplus/LookupItem.cpp index 7fc73ba2406..f4fce6e4edf 100644 --- a/src/libs/cplusplus/LookupItem.cpp +++ b/src/libs/cplusplus/LookupItem.cpp @@ -33,10 +33,10 @@ using namespace CPlusPlus; -uint CPlusPlus::qHash(const LookupItem &key) +Utils::QHashValueType CPlusPlus::qHash(const LookupItem &key) { - const uint h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type()); - const uint h2 = QT_PREPEND_NAMESPACE(qHash)(key.scope()); + const Utils::QHashValueType h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type()); + const Utils::QHashValueType h2 = QT_PREPEND_NAMESPACE(qHash)(key.scope()); return ((h1 << 16) | (h1 >> 16)) ^ h2; } diff --git a/src/libs/cplusplus/LookupItem.h b/src/libs/cplusplus/LookupItem.h index e2683c28778..bc760f8d8b5 100644 --- a/src/libs/cplusplus/LookupItem.h +++ b/src/libs/cplusplus/LookupItem.h @@ -26,6 +26,7 @@ #pragma once #include +#include #include @@ -70,6 +71,6 @@ private: ClassOrNamespace *_binding; }; -uint qHash(const CPlusPlus::LookupItem &result); +Utils::QHashValueType qHash(const CPlusPlus::LookupItem &result); } // namespace CPlusPlus diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index ea83933b7ed..e3b2b070803 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -155,7 +155,7 @@ using namespace ExtensionSystem::Internal; \fn uint ExtensionSystem::qHash(const ExtensionSystem::PluginDependency &value) \internal */ -uint ExtensionSystem::qHash(const PluginDependency &value) +Utils::QHashValueType ExtensionSystem::qHash(const PluginDependency &value) { return qHash(value.name); } diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h index d8d85ba5201..4b2bcc13063 100644 --- a/src/libs/extensionsystem/pluginspec.h +++ b/src/libs/extensionsystem/pluginspec.h @@ -27,6 +27,8 @@ #include "extensionsystem_global.h" +#include + #include #include #include @@ -65,7 +67,7 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency QString toString() const; }; -uint qHash(const ExtensionSystem::PluginDependency &value); +Utils::QHashValueType qHash(const ExtensionSystem::PluginDependency &value); struct EXTENSIONSYSTEM_EXPORT PluginArgumentDescription { diff --git a/src/libs/modelinglib/qmt/infrastructure/handle.h b/src/libs/modelinglib/qmt/infrastructure/handle.h index b7333a11464..7558ec96999 100644 --- a/src/libs/modelinglib/qmt/infrastructure/handle.h +++ b/src/libs/modelinglib/qmt/infrastructure/handle.h @@ -74,7 +74,7 @@ private: }; template -inline int qHash(const Handle &handle) +inline auto qHash(const Handle &handle) { return qHash(handle.uid()); } diff --git a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp index f2da9a9292c..47706f91fc8 100644 --- a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp +++ b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp @@ -38,6 +38,7 @@ #include "qmt/infrastructure/qmtassert.h" #include +#include #include @@ -82,7 +83,7 @@ public: ObjectVisuals m_objectVisuals; }; -uint qHash(const ObjectStyleKey &styleKey) +Utils::QHashValueType qHash(const ObjectStyleKey &styleKey) { return ::qHash(styleKey.m_elementType) ^ qHash(styleKey.m_objectVisuals); } @@ -106,7 +107,7 @@ public: DObject::VisualPrimaryRole m_visualPrimaryRole = DObject::PrimaryRoleNormal; }; -uint qHash(const RelationStyleKey &styleKey) +Utils::QHashValueType qHash(const RelationStyleKey &styleKey) { return ::qHash(styleKey.m_elementType) ^ ::qHash(styleKey.m_visualPrimaryRole); } @@ -127,7 +128,7 @@ public: DAnnotation::VisualRole m_visualRole = DAnnotation::RoleNormal; }; -uint qHash(const AnnotationStyleKey &styleKey) +Utils::QHashValueType qHash(const AnnotationStyleKey &styleKey) { return ::qHash(styleKey.m_visualRole); } @@ -142,11 +143,11 @@ class BoundaryStyleKey { }; -uint qHash(const BoundaryStyleKey &styleKey) +Utils::QHashValueType qHash(const BoundaryStyleKey &styleKey) { Q_UNUSED(styleKey) - return 1; + return ::qHash(1); } bool operator==(const BoundaryStyleKey &lhs, const BoundaryStyleKey &rhs) @@ -162,11 +163,11 @@ class SwimlaneStyleKey { }; -uint qHash(const SwimlaneStyleKey &styleKey) +Utils::QHashValueType qHash(const SwimlaneStyleKey &styleKey) { Q_UNUSED(styleKey) - return 1; + return ::qHash(1); } bool operator==(const SwimlaneStyleKey &lhs, const SwimlaneStyleKey &rhs) diff --git a/src/libs/modelinglib/qmt/style/objectvisuals.cpp b/src/libs/modelinglib/qmt/style/objectvisuals.cpp index a4bdadc26e6..7db69f6965b 100644 --- a/src/libs/modelinglib/qmt/style/objectvisuals.cpp +++ b/src/libs/modelinglib/qmt/style/objectvisuals.cpp @@ -82,7 +82,7 @@ bool operator==(const ObjectVisuals &lhs, const ObjectVisuals &rhs) && lhs.depth() == rhs.depth(); } -uint qHash(const ObjectVisuals &objectVisuals) +Utils::QHashValueType qHash(const ObjectVisuals &objectVisuals) { return ::qHash(static_cast(objectVisuals.visualPrimaryRole())) ^ ::qHash(static_cast(objectVisuals.visualSecondaryRole())) diff --git a/src/libs/modelinglib/qmt/style/objectvisuals.h b/src/libs/modelinglib/qmt/style/objectvisuals.h index 0d708fe0a52..dcc4bee623b 100644 --- a/src/libs/modelinglib/qmt/style/objectvisuals.h +++ b/src/libs/modelinglib/qmt/style/objectvisuals.h @@ -27,6 +27,8 @@ #include "qmt/diagram/dobject.h" +#include + #include namespace qmt { @@ -60,6 +62,6 @@ private: }; bool operator==(const ObjectVisuals &lhs, const ObjectVisuals &rhs); -uint qHash(const ObjectVisuals &objectVisuals); +Utils::QHashValueType qHash(const ObjectVisuals &objectVisuals); } // namespace qmt diff --git a/src/libs/qmljs/qmljsdialect.cpp b/src/libs/qmljs/qmljsdialect.cpp index cfe71b2265d..d0b922a7201 100644 --- a/src/libs/qmljs/qmljsdialect.cpp +++ b/src/libs/qmljs/qmljsdialect.cpp @@ -221,9 +221,9 @@ QList Dialect::companionLanguages() const return langs; } -uint qHash(const Dialect &o) +Utils::QHashValueType qHash(const Dialect &o) { - return uint(o.dialect()); + return Utils::QHashValueType(o.dialect()); } QDebug operator << (QDebug &dbg, const Dialect &dialect) diff --git a/src/libs/qmljs/qmljsdialect.h b/src/libs/qmljs/qmljsdialect.h index a2f28225990..e5941642785 100644 --- a/src/libs/qmljs/qmljsdialect.h +++ b/src/libs/qmljs/qmljsdialect.h @@ -28,6 +28,7 @@ #include "qmljs_global.h" #include +#include #include #include @@ -73,7 +74,7 @@ private: Enum m_dialect; }; -QMLJS_EXPORT uint qHash(const Dialect &o); +QMLJS_EXPORT Utils::QHashValueType qHash(const Dialect &o); QMLJS_EXPORT QDebug operator << (QDebug &dbg, const Dialect &dialect); diff --git a/src/libs/qmljs/qmljsimportdependencies.cpp b/src/libs/qmljs/qmljsimportdependencies.cpp index 3cf94cb3424..757ff2c3881 100644 --- a/src/libs/qmljs/qmljsimportdependencies.cpp +++ b/src/libs/qmljs/qmljsimportdependencies.cpp @@ -502,9 +502,9 @@ QString ImportKey::toString() const return res; } -uint qHash(const ImportKey &info) +Utils::QHashValueType qHash(const ImportKey &info) { - uint res = ::qHash(info.type) ^ + Utils::QHashValueType res = ::qHash(info.type) ^ ::qHash(info.majorVersion) ^ ::qHash(info.minorVersion); foreach (const QString &s, info.splitPath) res = res ^ ::qHash(s); diff --git a/src/libs/qmljs/qmljsimportdependencies.h b/src/libs/qmljs/qmljsimportdependencies.h index 41f84915516..a05bf1b4087 100644 --- a/src/libs/qmljs/qmljsimportdependencies.h +++ b/src/libs/qmljs/qmljsimportdependencies.h @@ -29,6 +29,7 @@ #include "qmljsdialect.h" #include +#include #include #include @@ -117,7 +118,7 @@ public: QString toString() const; }; -uint qHash(const ImportKey &info); +Utils::QHashValueType qHash(const ImportKey &info); bool operator ==(const ImportKey &i1, const ImportKey &i2); bool operator !=(const ImportKey &i1, const ImportKey &i2); bool operator <(const ImportKey &i1, const ImportKey &i2); diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 9ae98e35309..47951eeb28d 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -175,7 +175,7 @@ bool FakeMetaObjectWithOrigin::operator ==(const FakeMetaObjectWithOrigin &o) co return fakeMetaObject == o.fakeMetaObject; } -uint qHash(const FakeMetaObjectWithOrigin &fmoo) +Utils::QHashValueType qHash(const FakeMetaObjectWithOrigin &fmoo) { return qHash(fmoo.fakeMetaObject); } diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 69293867857..7322541e1af 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -734,7 +735,7 @@ public: bool operator ==(const FakeMetaObjectWithOrigin &o) const; }; -QMLJS_EXPORT uint qHash(const FakeMetaObjectWithOrigin &fmoo); +QMLJS_EXPORT Utils::QHashValueType qHash(const FakeMetaObjectWithOrigin &fmoo); class QMLJS_EXPORT CppQmlTypes { diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 4fcdb0a748d..58ead76afc4 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -32,6 +32,7 @@ #include "qmljsmodelmanagerinterface.h" #include "qmljsconstants.h" +#include #include #include @@ -54,7 +55,7 @@ public: {} private: - friend uint qHash(const ImportCacheKey &); + friend Utils::QHashValueType qHash(const ImportCacheKey &); friend bool operator==(const ImportCacheKey &, const ImportCacheKey &); int m_type; @@ -63,7 +64,7 @@ private: int m_minorVersion; }; -uint qHash(const ImportCacheKey &info) +Utils::QHashValueType qHash(const ImportCacheKey &info) { return ::qHash(info.m_type) ^ ::qHash(info.m_path) ^ ::qHash(info.m_majorVersion) ^ ::qHash(info.m_minorVersion); diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index ce6d0cc2cdd..065f96809e9 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1298,7 +1298,7 @@ FilePath FilePath::stringAppended(const QString &str) const return fn; } -uint FilePath::hash(uint seed) const +QHashValueType FilePath::hash(uint seed) const { if (Utils::HostOsInfo::fileNameCaseSensitivity() == Qt::CaseInsensitive) return qHash(m_data.toUpper(), seed); diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 474f2c1416c..a83c0aa5177 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -26,6 +26,7 @@ #pragma once #include "utils_global.h" +#include "porting.h" #include "hostosinfo.h" @@ -140,7 +141,7 @@ public: void clear(); bool isEmpty() const; - uint hash(uint seed) const; + QHashValueType hash(uint seed) const; [[nodiscard]] FilePath resolvePath(const FilePath &tail) const; [[nodiscard]] FilePath resolvePath(const QString &tail) const; @@ -201,7 +202,7 @@ private: using FilePaths = QList; -inline uint qHash(const Utils::FilePath &a, uint seed = 0) +inline QHashValueType qHash(const Utils::FilePath &a, uint seed = 0) { return a.hash(seed); } diff --git a/src/libs/utils/id.cpp b/src/libs/utils/id.cpp index 26430a29385..1349dd84882 100644 --- a/src/libs/utils/id.cpp +++ b/src/libs/utils/id.cpp @@ -84,7 +84,7 @@ static bool operator==(const StringHolder &sh1, const StringHolder &sh2) } -static uint qHash(const StringHolder &sh) +static auto qHash(const StringHolder &sh) { return QT_PREPEND_NAMESPACE(qHash)(sh.h, 0); } diff --git a/src/libs/utils/id.h b/src/libs/utils/id.h index e0af61099c8..5c6440bd56f 100644 --- a/src/libs/utils/id.h +++ b/src/libs/utils/id.h @@ -26,6 +26,7 @@ #pragma once #include "utils_global.h" +#include "porting.h" #include #include @@ -79,7 +80,7 @@ private: quintptr m_id = 0; }; -inline uint qHash(Id id) { return static_cast(id.uniqueIdentifier()); } +inline QHashValueType qHash(Id id) { return static_cast(id.uniqueIdentifier()); } } // namespace Utils diff --git a/src/libs/utils/link.cpp b/src/libs/utils/link.cpp index 884936a7bb9..1df67837b19 100644 --- a/src/libs/utils/link.cpp +++ b/src/libs/utils/link.cpp @@ -63,7 +63,7 @@ Link Link::fromFilePath(const FilePath &filePath, bool canContainLineNumber, QSt return Link{filePath.withNewPath(fileName.left(postfixPos)), lineColumn.line, lineColumn.column}; } -uint qHash(const Link &l) +QHashValueType qHash(const Link &l) { QString s = l.targetFilePath.toString(); return qHash(s.append(':').append(QString::number(l.targetLine)).append(':') diff --git a/src/libs/utils/link.h b/src/libs/utils/link.h index 34c2c5a5cfa..6d9fbb8ac1e 100644 --- a/src/libs/utils/link.h +++ b/src/libs/utils/link.h @@ -25,7 +25,8 @@ #pragma once -#include +#include "fileutils.h" +#include "porting.h" #include #include @@ -75,7 +76,7 @@ public: int targetColumn; }; -uint QTCREATOR_UTILS_EXPORT qHash(const Link &l); +QTCREATOR_UTILS_EXPORT QHashValueType qHash(const Link &l); using ProcessLinkCallback = std::function; diff --git a/src/plugins/clangtools/clangtoolsdiagnostic.cpp b/src/plugins/clangtools/clangtoolsdiagnostic.cpp index 7fe7098c22f..42ec9f5f2af 100644 --- a/src/plugins/clangtools/clangtoolsdiagnostic.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnostic.cpp @@ -62,7 +62,7 @@ QIcon Diagnostic::icon() const return {}; } -quint32 qHash(const Diagnostic &diagnostic) +Utils::QHashValueType qHash(const Diagnostic &diagnostic) { return qHash(diagnostic.name) ^ qHash(diagnostic.description) diff --git a/src/plugins/clangtools/clangtoolsdiagnostic.h b/src/plugins/clangtools/clangtoolsdiagnostic.h index e64d91a29f2..10534ff0b22 100644 --- a/src/plugins/clangtools/clangtoolsdiagnostic.h +++ b/src/plugins/clangtools/clangtoolsdiagnostic.h @@ -27,6 +27,8 @@ #include +#include + #include #include #include @@ -68,7 +70,7 @@ bool operator==(const Diagnostic &lhs, const Diagnostic &rhs); using Diagnostics = QList; -quint32 qHash(const Diagnostic &diagnostic); +Utils::QHashValueType qHash(const Diagnostic &diagnostic); } // namespace Internal } // namespace ClangTools diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index 93e6e6232af..bd5556d215c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -472,7 +472,7 @@ bool CMakeConfigItem::operator==(const CMakeConfigItem &o) const return o.key == key && o.value == value && o.isUnset == isUnset; } -uint qHash(const CMakeConfigItem &it) +Utils::QHashValueType qHash(const CMakeConfigItem &it) { return ::qHash(it.key) ^ ::qHash(it.value) ^ ::qHash(it.isUnset); } diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h index dae93455d72..19bbbfd7d66 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h @@ -27,6 +27,7 @@ #include "cmake_global.h" +#include #include #include @@ -78,7 +79,7 @@ public: QStringList values; }; -uint qHash(const CMakeConfigItem &it); // needed for MSVC +Utils::QHashValueType qHash(const CMakeConfigItem &it); // needed for MSVC class CMAKE_EXPORT CMakeConfig : public QList { diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.h b/src/plugins/cmakeprojectmanager/fileapidataextractor.h index 2b65c76e079..1bc99bf1a8b 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.h +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.h @@ -56,7 +56,7 @@ public: bool isGenerated = false; }; -inline uint qHash(const CMakeFileInfo &info, uint seed = 0) { return info.path.hash(seed); } +inline auto qHash(const CMakeFileInfo &info, uint seed = 0) { return info.path.hash(seed); } class FileApiQtcData { diff --git a/src/plugins/cppcheck/cppcheckdiagnostic.cpp b/src/plugins/cppcheck/cppcheckdiagnostic.cpp index 6534018fc52..a1b8235e820 100644 --- a/src/plugins/cppcheck/cppcheckdiagnostic.cpp +++ b/src/plugins/cppcheck/cppcheckdiagnostic.cpp @@ -34,7 +34,7 @@ bool Diagnostic::operator==(const Diagnostic &r) const == std::tie(r.severity, r.message, r.fileName, r.lineNumber); } -quint32 qHash(const Diagnostic &diagnostic) +Utils::QHashValueType qHash(const Diagnostic &diagnostic) { return qHash(diagnostic.message) ^ qHash(diagnostic.fileName) ^ diagnostic.lineNumber; } diff --git a/src/plugins/cppcheck/cppcheckdiagnostic.h b/src/plugins/cppcheck/cppcheckdiagnostic.h index eea6ef430e6..1983af68de3 100644 --- a/src/plugins/cppcheck/cppcheckdiagnostic.h +++ b/src/plugins/cppcheck/cppcheckdiagnostic.h @@ -26,6 +26,7 @@ #pragma once #include +#include namespace Cppcheck { namespace Internal { @@ -49,7 +50,7 @@ public: int lineNumber = 0; }; -quint32 qHash(const Diagnostic &diagnostic); +Utils::QHashValueType qHash(const Diagnostic &diagnostic); } // namespace Internal } // namespace Cppcheck diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index f0ab3becb03..38ab02e0a9e 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1285,7 +1285,7 @@ public: << quoteUnprintable(m_text); } - friend uint qHash(const Input &i) + friend auto qHash(const Input &i) { return ::qHash(i.m_key); } diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp index 79fddd37791..7fafba0ef48 100644 --- a/src/plugins/ios/iosprobe.cpp +++ b/src/plugins/ios/iosprobe.cpp @@ -160,12 +160,12 @@ bool XcodePlatform::operator==(const XcodePlatform &other) const return developerPath == other.developerPath; } -uint qHash(const XcodePlatform &platform) +Utils::QHashValueType qHash(const XcodePlatform &platform) { return qHash(platform.developerPath); } -uint qHash(const XcodePlatform::ToolchainTarget &target) +Utils::QHashValueType qHash(const XcodePlatform::ToolchainTarget &target) { return qHash(target.name); } diff --git a/src/plugins/ios/iosprobe.h b/src/plugins/ios/iosprobe.h index 52cf3015c53..966f669d087 100644 --- a/src/plugins/ios/iosprobe.h +++ b/src/plugins/ios/iosprobe.h @@ -24,6 +24,9 @@ ****************************************************************************/ #pragma once + +#include + #include #include #include @@ -61,8 +64,8 @@ public: bool operator==(const XcodePlatform &other) const; }; -uint qHash(const XcodePlatform &platform); -uint qHash(const XcodePlatform::ToolchainTarget &target); +Utils::QHashValueType qHash(const XcodePlatform &platform); +Utils::QHashValueType qHash(const XcodePlatform::ToolchainTarget &target); class XcodeProbe { diff --git a/src/plugins/modeleditor/modelindexer.cpp b/src/plugins/modeleditor/modelindexer.cpp index be4e49d9cdb..d05cf9ecb3d 100644 --- a/src/plugins/modeleditor/modelindexer.cpp +++ b/src/plugins/modeleditor/modelindexer.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,7 @@ namespace Internal { class ModelIndexer::QueuedFile { - friend uint qHash(const ModelIndexer::QueuedFile &queuedFile); + friend Utils::QHashValueType qHash(const ModelIndexer::QueuedFile &queuedFile); friend bool operator==(const ModelIndexer::QueuedFile &lhs, const ModelIndexer::QueuedFile &rhs); @@ -99,7 +100,7 @@ bool operator==(const ModelIndexer::QueuedFile &lhs, const ModelIndexer::QueuedF return lhs.m_file == rhs.m_file && lhs.m_project == rhs.m_project; } -uint qHash(const ModelIndexer::QueuedFile &queuedFile) +Utils::QHashValueType qHash(const ModelIndexer::QueuedFile &queuedFile) { return qHash(queuedFile.m_project) + qHash(queuedFile.m_project); } diff --git a/src/plugins/modeleditor/modelindexer.h b/src/plugins/modeleditor/modelindexer.h index 708ec26e9b4..e6df8bdeed2 100644 --- a/src/plugins/modeleditor/modelindexer.h +++ b/src/plugins/modeleditor/modelindexer.h @@ -25,6 +25,8 @@ #pragma once +#include + #include namespace qmt { class Uid; } @@ -50,7 +52,7 @@ class ModelIndexer : class DiagramsCollectorVisitor; class ModelIndexerPrivate; - friend uint qHash(const ModelIndexer::QueuedFile &queuedFile); + friend Utils::QHashValueType qHash(const ModelIndexer::QueuedFile &queuedFile); friend bool operator==(const ModelIndexer::QueuedFile &lhs, const ModelIndexer::QueuedFile &rhs); diff --git a/src/plugins/projectexplorer/buildtargetinfo.h b/src/plugins/projectexplorer/buildtargetinfo.h index 7d786de3ca7..34d5f196244 100644 --- a/src/plugins/projectexplorer/buildtargetinfo.h +++ b/src/plugins/projectexplorer/buildtargetinfo.h @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -48,7 +49,7 @@ public: bool isQtcRunnable = true; bool usesTerminal = false; - uint runEnvModifierHash = 0; // Make sure to update this when runEnvModifier changes! + Utils::QHashValueType runEnvModifierHash = 0; // Make sure to update this when runEnvModifier changes! std::function runEnvModifier; }; diff --git a/src/plugins/projectexplorer/deployablefile.cpp b/src/plugins/projectexplorer/deployablefile.cpp index 78fbcb165e7..7ecfb59409c 100644 --- a/src/plugins/projectexplorer/deployablefile.cpp +++ b/src/plugins/projectexplorer/deployablefile.cpp @@ -53,7 +53,7 @@ bool DeployableFile::isExecutable() const return m_type == TypeExecutable; } -uint qHash(const DeployableFile &d) +Utils::QHashValueType qHash(const DeployableFile &d) { return qHash(qMakePair(d.localFilePath().toString(), d.remoteDirectory())); } diff --git a/src/plugins/projectexplorer/deployablefile.h b/src/plugins/projectexplorer/deployablefile.h index 4709206b16d..e3760e4a02b 100644 --- a/src/plugins/projectexplorer/deployablefile.h +++ b/src/plugins/projectexplorer/deployablefile.h @@ -28,6 +28,7 @@ #include "projectexplorer_export.h" #include +#include #include @@ -71,6 +72,6 @@ inline bool operator!=(const DeployableFile &d1, const DeployableFile &d2) return !(d1 == d2); } -PROJECTEXPLORER_EXPORT uint qHash(const DeployableFile &d); +PROJECTEXPLORER_EXPORT Utils::QHashValueType qHash(const DeployableFile &d); } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/expanddata.cpp b/src/plugins/projectexplorer/expanddata.cpp index bf3876475d7..4b005b8fe50 100644 --- a/src/plugins/projectexplorer/expanddata.cpp +++ b/src/plugins/projectexplorer/expanddata.cpp @@ -50,7 +50,7 @@ QVariant ExpandData::toSettings() const return QVariant::fromValue(QStringList({path, displayName})); } -int ProjectExplorer::Internal::qHash(const ExpandData &data) +Utils::QHashValueType ProjectExplorer::Internal::qHash(const ExpandData &data) { return qHash(data.path) ^ qHash(data.displayName); } diff --git a/src/plugins/projectexplorer/expanddata.h b/src/plugins/projectexplorer/expanddata.h index 9d6a6564495..a7ff078680b 100644 --- a/src/plugins/projectexplorer/expanddata.h +++ b/src/plugins/projectexplorer/expanddata.h @@ -25,6 +25,8 @@ #pragma once +#include + #include #include #include @@ -46,7 +48,7 @@ public: QString displayName; }; -int qHash(const ExpandData &data); +Utils::QHashValueType qHash(const ExpandData &data); } // namespace Internal } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index fe880442ba4..3ef9e397a96 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -171,7 +171,7 @@ bool operator<(const Task &a, const Task &b) } -uint qHash(const Task &task) +Utils::QHashValueType qHash(const Task &task) { return task.taskId; } diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h index a21332c7087..b95d51d34ef 100644 --- a/src/plugins/projectexplorer/task.h +++ b/src/plugins/projectexplorer/task.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -135,13 +136,13 @@ public: using Tasks = QVector; -bool PROJECTEXPLORER_EXPORT operator==(const Task &t1, const Task &t2); -uint PROJECTEXPLORER_EXPORT qHash(const Task &task); +PROJECTEXPLORER_EXPORT bool operator==(const Task &t1, const Task &t2); +PROJECTEXPLORER_EXPORT Utils::QHashValueType qHash(const Task &task); -bool PROJECTEXPLORER_EXPORT operator<(const Task &a, const Task &b); +PROJECTEXPLORER_EXPORT bool operator<(const Task &a, const Task &b); -QString PROJECTEXPLORER_EXPORT toHtml(const Tasks &issues); -bool PROJECTEXPLORER_EXPORT containsType(const Tasks &issues, Task::TaskType); +PROJECTEXPLORER_EXPORT QString toHtml(const Tasks &issues); +PROJECTEXPLORER_EXPORT bool containsType(const Tasks &issues, Task::TaskType); } //namespace ProjectExplorer diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index f64aecd2962..b9c048764ed 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -69,8 +69,8 @@ namespace QmakeProjectManager { static Q_LOGGING_CATEGORY(qmakeParse, "qtc.qmake.parsing", QtWarningMsg); -uint qHash(Variable key, uint seed) { return ::qHash(static_cast(key), seed); } -uint qHash(FileOrigin fo) { return ::qHash(int(fo)); } +Utils::QHashValueType qHash(Variable key, uint seed) { return ::qHash(static_cast(key), seed); } +Utils::QHashValueType qHash(FileOrigin fo) { return ::qHash(int(fo)); } namespace Internal { diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index cfa86b181f8..9a4a22690e2 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -109,7 +110,7 @@ enum class Variable { QmakeCc, QmakeCxx }; -uint qHash(Variable key, uint seed = 0); +Utils::QHashValueType qHash(Variable key, uint seed = 0); namespace Internal { Q_DECLARE_LOGGING_CATEGORY(qmakeNodesLog) @@ -121,7 +122,7 @@ class QmakePriFileEvalResult; class InstallsList; enum class FileOrigin { ExactParse, CumulativeParse }; -uint qHash(FileOrigin fo); +Utils::QHashValueType qHash(FileOrigin fo); using SourceFile = QPair; using SourceFiles = QSet; diff --git a/src/plugins/qmldesigner/designercore/include/import.h b/src/plugins/qmldesigner/designercore/include/import.h index 99612fa2ada..c797a19ae45 100644 --- a/src/plugins/qmldesigner/designercore/include/import.h +++ b/src/plugins/qmldesigner/designercore/include/import.h @@ -25,6 +25,8 @@ #pragma once +#include + #include #include #include @@ -74,7 +76,7 @@ private: QStringList m_importPathList; }; -QMLDESIGNERCORE_EXPORT uint qHash(const Import &import); +QMLDESIGNERCORE_EXPORT Utils::QHashValueType qHash(const Import &import); } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/import.cpp b/src/plugins/qmldesigner/designercore/model/import.cpp index d895b07764c..1c217bf47b7 100644 --- a/src/plugins/qmldesigner/designercore/model/import.cpp +++ b/src/plugins/qmldesigner/designercore/model/import.cpp @@ -109,7 +109,7 @@ int Import::majorFromVersion(const QString &version) return version.split('.').first().toInt(); } -uint qHash(const Import &import) +Utils::QHashValueType qHash(const Import &import) { return ::qHash(import.url()) ^ ::qHash(import.file()) ^ ::qHash(import.version()) ^ ::qHash(import.alias()); } diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp index 054cc31eaec..8dcd41cbb4f 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp @@ -36,7 +36,7 @@ namespace QmlProfiler { -inline uint qHash(const QmlEventType &type) +inline auto qHash(const QmlEventType &type) { return qHash(type.location()) ^ (((type.message() << 12) & 0xf000) // 4 bits of message diff --git a/src/plugins/remotelinux/deploymenttimeinfo.cpp b/src/plugins/remotelinux/deploymenttimeinfo.cpp index 3130aadf20c..81eb9417e30 100644 --- a/src/plugins/remotelinux/deploymenttimeinfo.cpp +++ b/src/plugins/remotelinux/deploymenttimeinfo.cpp @@ -61,7 +61,7 @@ public: QString sysroot; }; -uint qHash(const DeployParameters &p) { +auto qHash(const DeployParameters &p) { return qHash(qMakePair(qMakePair(p.file, p.host), p.sysroot)); } diff --git a/src/plugins/texteditor/codeassist/genericproposalmodel.cpp b/src/plugins/texteditor/codeassist/genericproposalmodel.cpp index 96492caadbe..d0343b11bf4 100644 --- a/src/plugins/texteditor/codeassist/genericproposalmodel.cpp +++ b/src/plugins/texteditor/codeassist/genericproposalmodel.cpp @@ -41,7 +41,7 @@ using namespace TextEditor; QT_BEGIN_NAMESPACE -uint qHash(const AssistProposalItem &item) +auto qHash(const AssistProposalItem &item) { return qHash(item.text()); } diff --git a/src/plugins/texteditor/fontsettings.cpp b/src/plugins/texteditor/fontsettings.cpp index e35ed5c3b21..4c6df391ce2 100644 --- a/src/plugins/texteditor/fontsettings.cpp +++ b/src/plugins/texteditor/fontsettings.cpp @@ -141,7 +141,7 @@ bool FontSettings::equals(const FontSettings &f) const && m_scheme == f.m_scheme; } -uint qHash(const TextStyle &textStyle) +auto qHash(const TextStyle &textStyle) { return ::qHash(quint8(textStyle)); } @@ -202,7 +202,7 @@ QTextCharFormat FontSettings::toTextCharFormat(TextStyle category) const return tf; } -uint qHash(TextStyles textStyles) +auto qHash(TextStyles textStyles) { return ::qHash(reinterpret_cast(textStyles)); } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 1d236b497fb..90d141808a5 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -8255,7 +8255,7 @@ IEditor *BaseTextEditor::duplicate() QT_BEGIN_NAMESPACE -uint qHash(const QColor &color) +Utils::QHashValueType qHash(const QColor &color) { return color.rgba(); } diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 38cbdd01d31..5811f466e43 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -685,6 +686,6 @@ private: QT_BEGIN_NAMESPACE -uint qHash(const QColor &color); +Utils::QHashValueType qHash(const QColor &color); QT_END_NAMESPACE diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 1f4a436115e..8980e4c216e 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -114,7 +114,7 @@ uint ProString::updatedHash() const return (m_hash = hash(m_string.constData() + m_offset, m_length)); } -uint qHash(const ProString &str) +Utils::QHashValueType qHash(const ProString &str) { if (!(str.m_hash & 0x80000000)) return str.m_hash; diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index a16e0399d1e..4da7e5444bc 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -182,7 +182,7 @@ private: int m_file; mutable uint m_hash; uint updatedHash() const; - friend uint qHash(const ProString &str); + friend Utils::QHashValueType qHash(const ProString &str); friend QString operator+(const ProString &one, const ProString &two); friend class ProKey; }; @@ -253,7 +253,7 @@ template <> struct QConcatenable : private QAbstractConcatenable }; -uint qHash(const ProString &str); +Utils::QHashValueType qHash(const ProString &str); inline QString &operator+=(QString &that, const ProString &other) { return that += other.toStringView(); } diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index ff87a1b8f40..b937037b1e6 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -104,7 +104,7 @@ QMakeBaseKey::QMakeBaseKey(const QString &_root, const QString &_stash, bool _ho { } -uint qHash(const QMakeBaseKey &key) +Utils::QHashValueType qHash(const QMakeBaseKey &key) { return qHash(key.root) ^ qHash(key.stash) ^ (uint)key.hostBuild; } diff --git a/src/shared/proparser/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h index 2baeab4bf58..36b1c08c412 100644 --- a/src/shared/proparser/qmakeglobals.h +++ b/src/shared/proparser/qmakeglobals.h @@ -27,6 +27,7 @@ #include "qmake_global.h" #include "proitems.h" +#include #ifdef QT_BUILD_QMAKE # include @@ -58,7 +59,7 @@ public: bool hostBuild; }; -uint qHash(const QMakeBaseKey &key); +Utils::QHashValueType qHash(const QMakeBaseKey &key); bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two); class QMakeBaseEnv From cb946ec3078312c3d29ec456805803e55c38717d Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 11 Oct 2021 11:15:47 +0200 Subject: [PATCH 113/117] QmlDesigner: Support multiple module ids per type The type will be use source id and name instead of module id and name as key. Task-number: QDS-5236 Task-number: QDS-5238 Change-Id: Ibc9c298dc0a6363b630173ec4981d574cecd02ff Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Bot --- src/libs/utils/set_algorithm.h | 18 + .../projectstorage/projectstorage.h | 832 +++--- .../projectstorage/projectstorageinterface.h | 5 +- .../projectstorage/projectstoragetypes.h | 131 +- .../projectstorage/projectstorageupdater.cpp | 23 +- .../projectstorage/qmldocumentparser.cpp | 18 +- .../projectstorage/qmldocumentparser.h | 8 +- .../projectstorage/qmltypesparser.cpp | 72 +- .../projectstorage/qmltypesparser.h | 8 +- .../unit/unittest/gtest-creator-printing.cpp | 26 +- tests/unit/unittest/gtest-creator-printing.h | 4 - tests/unit/unittest/projectstorage-test.cpp | 2630 +++++++---------- tests/unit/unittest/projectstoragemock.h | 5 +- .../unittest/projectstorageupdater-test.cpp | 177 +- .../unit/unittest/qmldocumentparser-test.cpp | 20 +- tests/unit/unittest/qmltypesparser-test.cpp | 64 +- 16 files changed, 1835 insertions(+), 2206 deletions(-) diff --git a/src/libs/utils/set_algorithm.h b/src/libs/utils/set_algorithm.h index 42a21f3f2d7..97e33a047fc 100644 --- a/src/libs/utils/set_algorithm.h +++ b/src/libs/utils/set_algorithm.h @@ -99,6 +99,24 @@ bool set_intersection_compare( return false; } +template +void set_greedy_difference( + InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable call, Compare comp) +{ + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + call(*first1++); + } else if (comp(*first2, *first1)) { + ++first2; + } else { + ++first1; + } + } + + while (first1 != last1) + call(*first1++); +} + template Value mismatch_collect(InputIt1 first1, InputIt1 last1, diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 9bd49ef467d..f6412d231b4 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -28,6 +28,7 @@ #include "projectstorageexceptions.h" #include "projectstorageinterface.h" #include "sourcepathcachetypes.h" +#include "storagecache.h" #include #include @@ -35,7 +36,9 @@ #include #include +#include +#include #include namespace QmlDesigner { @@ -53,18 +56,24 @@ public: ProjectStorage(Database &database, bool isInitialized) : database{database} , initializer{database, isInitialized} - {} + { + moduleCache.populate(); + } - void synchronize(Storage::Modules modules, - Storage::Imports imports, + void synchronize(Storage::Imports imports, Storage::Types types, SourceIds sourceIds, FileStatuses fileStatuses) override { Sqlite::ImmediateTransaction transaction{database}; - std::vector insertedAliasPropertyDeclarations; - std::vector updatedAliasPropertyDeclarations; + AliasPropertyDeclarations insertedAliasPropertyDeclarations; + AliasPropertyDeclarations updatedAliasPropertyDeclarations; + + AliasPropertyDeclarations relinkableAliasPropertyDeclarations; + PropertyDeclarations relinkablePropertyDeclarations; + Prototypes relinkablePrototypes; + TypeIds deletedTypeIds; TypeIds updatedTypeIds; updatedTypeIds.reserve(types.size()); @@ -78,40 +87,45 @@ public: std::sort(sourceIdValues.begin(), sourceIdValues.end()); synchronizeFileStatuses(fileStatuses, sourceIdValues); - synchronizeModules(modules, typeIdsToBeDeleted, sourceIdValues); synchronizeImports(imports, sourceIdValues); synchronizeTypes(types, updatedTypeIds, insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations); + updatedAliasPropertyDeclarations, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + sourceIdValues); - deleteNotUpdatedTypes(updatedTypeIds, sourceIdValues, typeIdsToBeDeleted); + deleteNotUpdatedTypes(updatedTypeIds, + sourceIdValues, + typeIdsToBeDeleted, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + deletedTypeIds); + + relink(relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + deletedTypeIds); linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); transaction.commit(); } - ModuleId fetchModuleId(Utils::SmallStringView moduleName) + ModuleId moduleId(Utils::SmallStringView moduleName) override { - Sqlite::DeferredTransaction transaction{database}; - - ModuleId moduleId = fetchModuleIdUnguarded(moduleName); - - transaction.commit(); - - return moduleId; + return moduleCache.id(moduleName); } - ModuleIds fetchModuleIds(const Storage::Modules &modules) + Utils::SmallString moduleName(ModuleId moduleId) { - Sqlite::DeferredTransaction transaction{database}; + if (!moduleId) + throw ModuleDoesNotExists{}; - ModuleIds moduleIds = fetchModuleIdsUnguarded(modules); - - transaction.commit(); - - return moduleIds; + return moduleCache.value(moduleId); } PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId, @@ -132,9 +146,9 @@ public: static_cast(moduleIds.data()), static_cast(moduleIds.size()), name); } - TypeId fetchTypeIdByName(ModuleId moduleId, Utils::SmallStringView name) + TypeId fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name) { - return selectTypeIdByModuleIdAndNameStatement.template valueWithTransaction(&moduleId, + return selectTypeIdBySourceIdAndNameStatement.template valueWithTransaction(&sourceId, name); } @@ -283,11 +297,6 @@ public: return writeSourceId(sourceContextId, sourceName); } - auto fetchAllModules() const - { - return selectAllModulesStatement.template valuesWithTransaction(128); - } - auto fetchAllFileStatuses() const { return selectAllFileStatusesStatement.template rangeWithTransaction(); @@ -302,6 +311,73 @@ public: SourceIds fetchSourceDependencieIds(SourceId sourceId) const override { return {}; } private: + class ModuleStorageAdapter + { + public: + auto fetchId(const Utils::SmallStringView name) { return storage.fetchModuleId(name); } + + auto fetchValue(ModuleId id) { return storage.fetchModuleName(id); } + + auto fetchAll() { return storage.fetchAllModules(); } + + ProjectStorage &storage; + }; + + class Module : public StorageCacheEntry + { + using Base = StorageCacheEntry; + + public: + using Base::Base; + + friend bool operator==(const Module &first, const Module &second) + { + return first.id == second.id && first.value == second.value; + } + }; + + friend ModuleStorageAdapter; + + static bool moduleNameLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept + { + return Utils::reverseCompare(first, second) < 0; + } + + using ModuleCache = StorageCache; + + ModuleId fetchModuleId(Utils::SmallStringView moduleName) + { + Sqlite::DeferredTransaction transaction{database}; + + ModuleId moduleId = fetchModuleIdUnguarded(moduleName); + + transaction.commit(); + + return moduleId; + } + + auto fetchModuleName(ModuleId id) + { + Sqlite::DeferredTransaction transaction{database}; + + auto moduleName = fetchModuleNameUnguarded(id); + + transaction.commit(); + + return moduleName; + } + + auto fetchAllModules() const + { + return selectAllModulesStatement.template valuesWithTransaction(128); + } + class AliasPropertyDeclaration { public: @@ -318,6 +394,13 @@ private: , aliasPropertyDeclarationId{aliasPropertyDeclarationId} {} + friend bool operator<(const AliasPropertyDeclaration &first, + const AliasPropertyDeclaration &second) + { + return std::tie(first.typeId, first.propertyDeclarationId) + < std::tie(second.typeId, second.propertyDeclarationId); + } + public: TypeId typeId; PropertyDeclarationId propertyDeclarationId; @@ -326,6 +409,8 @@ private: PropertyDeclarationId aliasPropertyDeclarationId; }; + using AliasPropertyDeclarations = std::vector; + class PropertyDeclaration { public: @@ -345,12 +430,20 @@ private: , importedTypeNameId{importedTypeNameId} {} + friend bool operator<(const PropertyDeclaration &first, const PropertyDeclaration &second) + { + return std::tie(first.typeId, first.propertyDeclarationId) + < std::tie(second.typeId, second.propertyDeclarationId); + } + public: TypeId typeId; PropertyDeclarationId propertyDeclarationId; ImportedTypeNameId importedTypeNameId; }; + using PropertyDeclarations = std::vector; + class Prototype { public: @@ -359,15 +452,58 @@ private: , prototypeNameId{std::move(prototypeNameId)} {} + friend bool operator<(Prototype first, Prototype second) + { + return first.typeId < second.typeId; + } + public: TypeId typeId; ImportedTypeNameId prototypeNameId; }; + using Prototypes = std::vector; + + template + struct TypeCompare + { + bool operator()(const Type &type, TypeId typeId) { return type.typeId < typeId; }; + + bool operator()(TypeId typeId, const Type &type) { return typeId < type.typeId; }; + + bool operator()(const Type &first, const Type &second) + { + return first.typeId < second.typeId; + }; + }; + + template + struct PropertyCompare + { + bool operator()(const Property &property, PropertyDeclarationId id) + { + return property.propertyDeclarationId < id; + }; + + bool operator()(PropertyDeclarationId id, const Property &property) + { + return id < property.propertyDeclarationId; + }; + + bool operator()(const Property &first, const Property &second) + { + return first.propertyDeclarationId < second.propertyDeclarationId; + }; + }; + void synchronizeTypes(Storage::Types &types, TypeIds &updatedTypeIds, - std::vector &insertedAliasPropertyDeclarations, - std::vector &updatedAliasPropertyDeclarations) + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + const std::vector &sourceIdValues) { Storage::ExportedTypes exportedTypes; exportedTypes.reserve(types.size() * 3); @@ -381,16 +517,19 @@ private: extractExportedTypes(typeId, type, exportedTypes); } - synchronizeExportedTypes(updatedTypeIds, exportedTypes); + synchronizeExportedTypes(sourceIdValues, + updatedTypeIds, + exportedTypes, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes); - for (auto &&type : types) - syncPrototypes(type); - - for (auto &&type : types) - resetRemovedAliasPropertyDeclarationsToNull(type.typeId, type.propertyDeclarations); - - for (auto &&type : types) - syncDeclarations(type, insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); + syncPrototypes(types, relinkablePrototypes); + resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations); + syncDeclarations(types, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + relinkablePropertyDeclarations); } void synchronizeFileStatuses(FileStatuses &fileStatuses, const std::vector &sourceIdValues) @@ -428,43 +567,10 @@ private: Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove); } - void synchronizeModules(Storage::Modules &modules, - TypeIds &typeIdsToBeDeleted, - const std::vector &moduleIdValues) - { - auto compareKey = [](auto &&first, auto &&second) { - return first.sourceId.id - second.sourceId.id; - }; - - std::sort(modules.begin(), modules.end(), [&](auto &&first, auto &&second) { - return compareKey(first, second) < 0; - }); - - auto range = selectModulesForIdsStatement.template range( - Utils::span(moduleIdValues)); - - auto insert = [&](Storage::Module &module) { - insertModuleStatement.write(module.name, &module.sourceId); - }; - - auto update = [&](const Storage::ModuleView &moduleView, Storage::Module &module) { - if (moduleView.name != module.name) - updateModuleStatement.write(&moduleView.sourceId, module.name); - }; - - auto remove = [&](const Storage::ModuleView &moduleView) { - deleteModuleStatement.write(&moduleView.sourceId); - selectTypeIdsForModuleIdStatement.readTo(typeIdsToBeDeleted, &moduleView.sourceId); - }; - - Sqlite::insertUpdateDelete(range, modules, compareKey, insert, update, remove); - } - void synchronizeImports(Storage::Imports &imports, std::vector &sourceIdValues) { deleteDocumentImportsForDeletedDocuments(imports, sourceIdValues); - addModuleIdToImports(imports); synchronizeDocumentImports(imports, sourceIdValues); } @@ -487,50 +593,28 @@ private: deleteDocumentImportsWithSourceIdsStatement.write(Utils::span{documentSourceIdsToBeDeleted}); } - void synchronizeModulesAndUpdatesModuleIds(Storage::Modules &modules, - TypeIds &typeIdsToBeDeleted, - const std::vector &moduleIds) - { - auto compareKey = [](auto &&first, auto &&second) { - return first.sourceId.id - second.sourceId.id; - }; - - std::sort(modules.begin(), modules.end(), [&](auto &&first, auto &&second) { - return compareKey(first, second) < 0; - }); - - auto range = selectModulesForIdsStatement.template range( - Utils::span(moduleIds)); - - auto insert = [&](Storage::Module &module) { - insertModuleStatement.write(module.name, &module.sourceId); - }; - - auto update = [&](const Storage::ModuleView &moduleView, Storage::Module &module) { - if (moduleView.name != module.name) - updateModuleStatement.write(&moduleView.sourceId, module.name); - }; - - auto remove = [&](const Storage::ModuleView &moduleView) { - deleteModuleStatement.write(&moduleView.sourceId); - selectTypeIdsForModuleIdStatement.readTo(typeIdsToBeDeleted, &moduleView.sourceId); - }; - - Sqlite::insertUpdateDelete(range, modules, compareKey, insert, update, remove); - } - - ModuleId fetchModuleIdUnguarded(const Storage::Module &module) const - { - return fetchModuleIdUnguarded(module.name); - } - ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const { - return selectModuleIdByNameStatement.template value(name); + auto moduleId = selectModuleIdByNameStatement.template value(name); + + if (moduleId) + return moduleId; + + return insertModuleNameStatement.template value(name); + } + + auto fetchModuleNameUnguarded(ModuleId id) const + { + auto moduleName = selectModuleNameStatement.template value(&id); + + if (moduleName.empty()) + throw ModuleDoesNotExists{}; + + return moduleName; } void handleAliasPropertyDeclarationsWithPropertyType( - TypeId typeId, std::vector &relinkableAliasPropertyDeclarations) + TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) { auto callback = [&](long long typeId, long long propertyDeclarationId, @@ -555,8 +639,7 @@ private: } void prepareLinkingOfAliasPropertiesDeclarationsWithAliasId( - PropertyDeclarationId aliasId, - std::vector &relinkableAliasPropertyDeclarations) + PropertyDeclarationId aliasId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) { auto callback = [&](long long propertyDeclarationId, long long propertyImportedTypeNameId, @@ -578,14 +661,14 @@ private: &aliasId); } - void handlePropertyDeclarationWithPropertyType( - TypeId typeId, std::vector &relinkablePropertyDeclarations) + void handlePropertyDeclarationWithPropertyType(TypeId typeId, + PropertyDeclarations &relinkablePropertyDeclarations) { updatesPropertyDeclarationPropertyTypeToNullStatement.readTo(relinkablePropertyDeclarations, &typeId); } - void handlePrototypes(TypeId prototypeId, std::vector &relinkablePrototypes) + void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes) { auto callback = [&](long long typeId, long long prototypeNameId) { relinkablePrototypes.emplace_back(TypeId{typeId}, ImportedTypeNameId{prototypeNameId}); @@ -597,9 +680,9 @@ private: } void deleteType(TypeId typeId, - std::vector &relinkableAliasPropertyDeclarations, - std::vector &relinkablePropertyDeclarations, - std::vector &relinkablePrototypes) + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes) { handlePropertyDeclarationWithPropertyType(typeId, relinkablePropertyDeclarations); handleAliasPropertyDeclarationsWithPropertyType(typeId, relinkableAliasPropertyDeclarations); @@ -612,72 +695,85 @@ private: deleteTypeStatement.write(&typeId); } - void relinkAliasPropertyDeclarations( - const std::vector &aliasPropertyDeclarations, - const TypeIds &deletedTypeIds) + void relinkAliasPropertyDeclarations(AliasPropertyDeclarations &aliasPropertyDeclarations, + const TypeIds &deletedTypeIds) { - for (const AliasPropertyDeclaration &alias : aliasPropertyDeclarations) { - if (std::binary_search(deletedTypeIds.begin(), deletedTypeIds.end(), alias.typeId)) - continue; + std::sort(aliasPropertyDeclarations.begin(), aliasPropertyDeclarations.end()); - auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); + Utils::set_greedy_difference( + aliasPropertyDeclarations.cbegin(), + aliasPropertyDeclarations.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const AliasPropertyDeclaration &alias) { + auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); - if (!typeId) - throw TypeNameDoesNotExists{}; + if (!typeId) + throw TypeNameDoesNotExists{}; - auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded( - typeId, alias.aliasPropertyName); + auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded( + typeId, alias.aliasPropertyName); - updatePropertyDeclarationWithAliasAndTypeStatement.write(&alias.propertyDeclarationId, - &propertyTypeId, - propertyTraits, - &alias.aliasImportedTypeNameId, - &aliasId); - } + updatePropertyDeclarationWithAliasAndTypeStatement.write(&alias.propertyDeclarationId, + &propertyTypeId, + propertyTraits, + &alias.aliasImportedTypeNameId, + &aliasId); + }, + TypeCompare{}); } - void relinkPropertyDeclarations(const std::vector &relinkablePropertyDeclaration, + void relinkPropertyDeclarations(PropertyDeclarations &relinkablePropertyDeclaration, const TypeIds &deletedTypeIds) { - for (const PropertyDeclaration &property : relinkablePropertyDeclaration) { - if (std::binary_search(deletedTypeIds.begin(), deletedTypeIds.end(), property.typeId)) - continue; + std::sort(relinkablePropertyDeclaration.begin(), relinkablePropertyDeclaration.end()); - TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId); + Utils::set_greedy_difference( + relinkablePropertyDeclaration.cbegin(), + relinkablePropertyDeclaration.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const PropertyDeclaration &property) { + TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId); - if (!propertyTypeId) - throw TypeNameDoesNotExists{}; + if (!propertyTypeId) + throw TypeNameDoesNotExists{}; - updatePropertyDeclarationTypeStatement.write(&property.propertyDeclarationId, - &propertyTypeId); - } + updatePropertyDeclarationTypeStatement.write(&property.propertyDeclarationId, + &propertyTypeId); + }, + TypeCompare{}); } - void relinkPrototypes(std::vector relinkablePrototypes, const TypeIds &deletedTypeIds) + void relinkPrototypes(Prototypes &relinkablePrototypes, const TypeIds &deletedTypeIds) { - for (const Prototype &prototype : relinkablePrototypes) { - if (std::binary_search(deletedTypeIds.begin(), deletedTypeIds.end(), prototype.typeId)) - continue; + std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end()); - TypeId prototypeId = fetchTypeId(prototype.prototypeNameId); + Utils::set_greedy_difference( + relinkablePrototypes.cbegin(), + relinkablePrototypes.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const Prototype &prototype) { + TypeId prototypeId = fetchTypeId(prototype.prototypeNameId); - if (!prototypeId) - throw TypeNameDoesNotExists{}; + if (!prototypeId) + throw TypeNameDoesNotExists{}; - updateTypePrototypeStatement.write(&prototype.typeId, &prototypeId); - checkForPrototypeChainCycle(prototype.typeId); - } + updateTypePrototypeStatement.write(&prototype.typeId, &prototypeId); + checkForPrototypeChainCycle(prototype.typeId); + }, + TypeCompare{}); } void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, const std::vector &sourceIdValues, - const TypeIds &typeIdsToBeDeleted) + const TypeIds &typeIdsToBeDeleted, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + TypeIds &deletedTypeIds) { - std::vector relinkableAliasPropertyDeclarations; - std::vector relinkablePropertyDeclarations; - std::vector relinkablePrototypes; - TypeIds deletedTypeIds; - auto updatedTypeIdValues = Utils::transform(updatedTypeIds, [](TypeId typeId) { return &typeId; }); @@ -696,7 +792,13 @@ private: Utils::span(updatedTypeIdValues)); for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted) callback(&typeIdToBeDeleted); + } + void relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + TypeIds &deletedTypeIds) + { std::sort(deletedTypeIds.begin(), deletedTypeIds.end()); relinkPrototypes(relinkablePrototypes, deletedTypeIds); @@ -704,7 +806,7 @@ private: relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds); } - void linkAliasPropertyDeclarationAliasIds(const std::vector &aliasDeclarations) + void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations) { for (const auto &aliasDeclaration : aliasDeclarations) { auto aliasTypeId = fetchTypeId(aliasDeclaration.aliasImportedTypeNameId); @@ -722,7 +824,7 @@ private: } } - void updateAliasPropertyDeclarationValues(const std::vector &aliasDeclarations) + void updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations) { for (const auto &aliasDeclaration : aliasDeclarations) { updatetPropertiesDeclarationValuesOfAliasStatement.write( @@ -732,14 +834,14 @@ private: } } - void checkAliasPropertyDeclarationCycles(const std::vector &aliasDeclarations) + void checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations) { for (const auto &aliasDeclaration : aliasDeclarations) checkForAliasChainCycle(aliasDeclaration.propertyDeclarationId); } - void linkAliases(const std::vector &insertedAliasPropertyDeclarations, - const std::vector &updatedAliasPropertyDeclarations) + void linkAliases(const AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + const AliasPropertyDeclarations &updatedAliasPropertyDeclarations) { linkAliasPropertyDeclarationAliasIds(insertedAliasPropertyDeclarations); linkAliasPropertyDeclarationAliasIds(updatedAliasPropertyDeclarations); @@ -751,16 +853,25 @@ private: updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations); } - void synchronizeExportedTypes(const TypeIds &typeIds, Storage::ExportedTypes &exportedTypes) + void synchronizeExportedTypes(const std::vector &sourceIdValues, + const TypeIds &updatedTypeIds, + Storage::ExportedTypes &exportedTypes, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes) { std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { return std::tie(first.moduleId, first.name, first.version) < std::tie(second.moduleId, second.name, second.version); }); - auto range = selectExportedTypesForTypeIdStatement.template range( - const_cast(static_cast(typeIds.data())), - static_cast(typeIds.size())); + Utils::span typeIdValues{static_cast( + &updatedTypeIds.data()->id), + updatedTypeIds.size()}; + + auto range = selectExportedTypesForSourceIdsStatement + .template range(Utils::span{sourceIdValues}, + typeIdValues); auto compareKey = [](const Storage::ExportedTypeView &view, const Storage::ExportedType &type) -> long long { @@ -780,53 +891,51 @@ private: }; auto insert = [&](const Storage::ExportedType &type) { + if (!type.moduleId) + throw QmlDesigner::ModuleDoesNotExists{}; + if (type.version) { - upsertExportedTypeNamesWithVersionStatement.write(&type.moduleId, + insertExportedTypeNamesWithVersionStatement.write(&type.moduleId, type.name, - static_cast( - Storage::TypeNameKind::Exported), type.version.major.value, type.version.minor.value, &type.typeId); } else if (type.version.major) { - upsertExportedTypeNamesWithMajorVersionStatement - .write(&type.moduleId, - type.name, - static_cast(Storage::TypeNameKind::Exported), - type.version.major.value, - &type.typeId); + insertExportedTypeNamesWithMajorVersionStatement.write(&type.moduleId, + type.name, + type.version.major.value, + &type.typeId); } else { - upsertExportedTypeNamesWithoutVersionStatement - .write(&type.moduleId, - type.name, - static_cast(Storage::TypeNameKind::Exported), - &type.typeId); + insertExportedTypeNamesWithoutVersionStatement.write(&type.moduleId, + type.name, + &type.typeId); } }; auto update = [&](const Storage::ExportedTypeView &view, const Storage::ExportedType &type) { - if (view.typeId != type.typeId) + if (view.typeId != type.typeId) { + handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(view.typeId, + relinkableAliasPropertyDeclarations); + handlePrototypes(view.typeId, relinkablePrototypes); updateExportedTypeNameTypeIdStatement.write(&view.exportedTypeNameId, &type.typeId); + } }; auto remove = [&](const Storage::ExportedTypeView &view) { + handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(view.typeId, + relinkableAliasPropertyDeclarations); + handlePrototypes(view.typeId, relinkablePrototypes); deleteExportedTypeNameStatement.write(&view.exportedTypeNameId); }; Sqlite::insertUpdateDelete(range, exportedTypes, compareKey, insert, update, remove); } - void upsertNativeType(ModuleId moduleId, Utils::SmallStringView name, TypeId typeId) - { - upsertExportedTypeNameStatement.write(&moduleId, - name, - static_cast(Storage::TypeNameKind::Native), - &typeId); - } - void synchronizePropertyDeclarationsInsertAlias( - std::vector &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, const Storage::PropertyDeclaration &value, SourceId sourceId, TypeId typeId) @@ -872,7 +981,7 @@ private: } void synchronizePropertyDeclarationsUpdateAlias( - std::vector &updatedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, const Storage::PropertyDeclarationView &view, const Storage::PropertyDeclaration &value, SourceId sourceId) @@ -887,7 +996,8 @@ private: void synchronizePropertyDeclarationsUpdateProperty(const Storage::PropertyDeclarationView &view, const Storage::PropertyDeclaration &value, - SourceId sourceId) + SourceId sourceId, + PropertyDeclarationIds &propertyDeclarationIds) { auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); @@ -906,14 +1016,15 @@ private: &propertyImportedTypeNameId); updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement .write(&view.id, &propertyTypeId, static_cast(value.traits)); + propertyDeclarationIds.push_back(view.id); } - void synchronizePropertyDeclarations( - TypeId typeId, - Storage::PropertyDeclarations &propertyDeclarations, - SourceId sourceId, - std::vector &insertedAliasPropertyDeclarations, - std::vector &updatedAliasPropertyDeclarations) + void synchronizePropertyDeclarations(TypeId typeId, + Storage::PropertyDeclarations &propertyDeclarations, + SourceId sourceId, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarationIds &propertyDeclarationIds) { std::sort(propertyDeclarations.begin(), propertyDeclarations.end(), @@ -947,8 +1058,12 @@ private: view, value, sourceId); + propertyDeclarationIds.push_back(view.id); } else { - synchronizePropertyDeclarationsUpdateProperty(view, value, sourceId); + synchronizePropertyDeclarationsUpdateProperty(view, + value, + sourceId, + propertyDeclarationIds); } }; @@ -962,14 +1077,20 @@ private: } deletePropertyDeclarationStatement.write(&view.id); + propertyDeclarationIds.push_back(view.id); }; Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove); } - void resetRemovedAliasPropertyDeclarationsToNull(TypeId typeId, - Storage::PropertyDeclarations &aliasDeclarations) + void resetRemovedAliasPropertyDeclarationsToNull(Storage::Type &type, + PropertyDeclarationIds &propertyDeclarationIds) { + if (type.changeLevel == Storage::ChangeLevel::Minimal) + return; + + Storage::PropertyDeclarations &aliasDeclarations = type.propertyDeclarations; + class AliasPropertyDeclarationView { public: @@ -992,7 +1113,7 @@ private: }); auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement - .template range(&typeId); + .template range(&type.typeId); auto compareKey = [](const AliasPropertyDeclarationView &view, const Storage::PropertyDeclaration &value) { @@ -1006,29 +1127,24 @@ private: auto remove = [&](const AliasPropertyDeclarationView &view) { updatePropertyDeclarationAliasIdToNullStatement.write(&view.id); + propertyDeclarationIds.push_back(view.id); }; Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove); } - ModuleIds fetchModuleIdsUnguarded(const Storage::Modules &modules) + void resetRemovedAliasPropertyDeclarationsToNull( + Storage::Types &types, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) { - ModuleIds moduleIds; - moduleIds.reserve(moduleIds.size()); + PropertyDeclarationIds propertyDeclarationIds; + propertyDeclarationIds.reserve(types.size()); - for (auto &&module : modules) - moduleIds.push_back(fetchModuleIdUnguarded(module)); + for (auto &&type : types) + resetRemovedAliasPropertyDeclarationsToNull(type, propertyDeclarationIds); - return moduleIds; - } - - void addModuleIdToImports(Storage::Imports &imports) - { - for (Storage::Import &import : imports) { - import.moduleId = fetchModuleIdUnguarded(import.name); - if (!import.moduleId) - throw ModuleDoesNotExists{}; - } + removeRelinkableEntries(relinkableAliasPropertyDeclarations, + propertyDeclarationIds, + PropertyCompare{}); } void synchronizeDocumentImports(Storage::Imports &imports, const std::vector &sourceIdValues) @@ -1257,60 +1373,88 @@ private: Storage::ExportedTypes &exportedTypes) { for (const auto &exportedType : type.exportedTypes) - exportedTypes.emplace_back(exportedType.name, exportedType.version, typeId, type.moduleId); + exportedTypes.emplace_back(exportedType.name, + exportedType.version, + typeId, + exportedType.moduleId); } - struct ModuleAndTypeId - { - ModuleAndTypeId() = default; - ModuleAndTypeId(int moduleId, long long typeId) - : moduleId{moduleId} - , typeId{typeId} - {} - - ModuleId moduleId; - TypeId typeId; - }; - TypeId declareType(Storage::Type &type) { - if (!type.moduleId && type.typeName.isEmpty()) { - auto [moduleId, typeId] = selectModuleAndTypeIdBySourceIdStatement - .template value(&type.sourceId); - type.typeId = typeId; - type.moduleId = moduleId; + if (type.typeName.isEmpty()) { + type.typeId = selectTypeIdBySourceIdStatement.template value(&type.sourceId); + return type.typeId; } - if (!type.moduleId) - throw ModuleDoesNotExists{}; - - type.typeId = upsertTypeStatement.template value(&type.moduleId, + type.typeId = upsertTypeStatement.template value(&type.sourceId, type.typeName, - static_cast(type.accessSemantics), - &type.sourceId); + static_cast( + type.accessSemantics)); if (!type.typeId) - type.typeId = selectTypeIdByModuleIdAndNameStatement.template value(&type.moduleId, + type.typeId = selectTypeIdBySourceIdAndNameStatement.template value(&type.sourceId, type.typeName); - upsertNativeType(type.moduleId, type.typeName, type.typeId); return type.typeId; } void syncDeclarations(Storage::Type &type, - std::vector &insertedAliasPropertyDeclarations, - std::vector &updatedAliasPropertyDeclarations) + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarationIds &propertyDeclarationIds) { - auto typeId = type.typeId; - synchronizePropertyDeclarations(typeId, + if (type.changeLevel == Storage::ChangeLevel::Minimal) + return; + + synchronizePropertyDeclarations(type.typeId, type.propertyDeclarations, type.sourceId, insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations); - synchronizeFunctionDeclarations(typeId, type.functionDeclarations); - synchronizeSignalDeclarations(typeId, type.signalDeclarations); - synchronizeEnumerationDeclarations(typeId, type.enumerationDeclarations); + updatedAliasPropertyDeclarations, + propertyDeclarationIds); + synchronizeFunctionDeclarations(type.typeId, type.functionDeclarations); + synchronizeSignalDeclarations(type.typeId, type.signalDeclarations); + synchronizeEnumerationDeclarations(type.typeId, type.enumerationDeclarations); + } + + template + void removeRelinkableEntries(std::vector &relinkables, Ids &ids, Compare compare) + { + std::vector newRelinkables; + newRelinkables.reserve(relinkables.size()); + + std::sort(ids.begin(), ids.end()); + std::sort(relinkables.begin(), relinkables.end(), compare); + + Utils::set_greedy_difference( + relinkables.begin(), + relinkables.end(), + ids.cbegin(), + ids.cend(), + [&](Relinkable &entry) { newRelinkables.push_back(std::move(entry)); }, + compare); + + relinkables = std::move(newRelinkables); + } + + void syncDeclarations(Storage::Types &types, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations) + { + PropertyDeclarationIds propertyDeclarationIds; + propertyDeclarationIds.reserve(types.size() * 10); + + for (auto &&type : types) + syncDeclarations(type, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + propertyDeclarationIds); + + removeRelinkableEntries(relinkablePropertyDeclarations, + propertyDeclarationIds, + PropertyCompare{}); } void checkForPrototypeChainCycle(TypeId typeId) const @@ -1338,7 +1482,7 @@ private: &propertyDeclarationId); } - void syncPrototypes(Storage::Type &type) + void syncPrototype(Storage::Type &type, TypeIds &typeIds) { if (type.changeLevel == Storage::ChangeLevel::Minimal) return; @@ -1358,22 +1502,35 @@ private: updatePrototypeStatement.write(&type.typeId, &prototypeId, &prototypeTypeNameId); checkForPrototypeChainCycle(type.typeId); } + + typeIds.push_back(type.typeId); + } + + void syncPrototypes(Storage::Types &types, Prototypes &relinkablePrototypes) + { + TypeIds typeIds; + typeIds.reserve(types.size()); + + for (auto &type : types) + syncPrototype(type, typeIds); + + removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare{}); } ImportId fetchImportId(SourceId sourceId, const Storage::Import &import) const { if (import.version) { - return selectImportIdBySourceIdAndImportNameAndVersionStatement.template value( - &sourceId, import.name, import.version.major.value, import.version.minor.value); + return selectImportIdBySourceIdAndModuleIdAndVersionStatement.template value( + &sourceId, &import.moduleId, import.version.major.value, import.version.minor.value); } if (import.version.major) { - return selectImportIdBySourceIdAndImportNameAndMajorVersionStatement - .template value(&sourceId, import.name, import.version.major.value); + return selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement + .template value(&sourceId, &import.moduleId, import.version.major.value); } - return selectImportIdBySourceIdAndImportNameStatement.template value(&sourceId, - import.name); + return selectImportIdBySourceIdAndModuleIdStatement.template value(&sourceId, + &import.moduleId); } ImportedTypeNameId fetchImportedTypeNameId(const Storage::ImportedTypeName &name, SourceId sourceId) @@ -1440,9 +1597,6 @@ private: &typeNameId); } - if (kind == Storage::TypeNameKind::Native) - return selectTypeIdForNativeTypeNameNamesStatement.template value(&typeNameId); - return selectTypeIdForImportedTypeNameNamesStatement.template value(&typeNameId); } @@ -1649,21 +1803,16 @@ private: typesTable.setUseIfNotExists(true); typesTable.setName("types"); typesTable.addColumn("typeId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); - auto &moduleIdColumn = typesTable.addForeignKeyColumn("moduleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::Enforment::Deferred); + auto &sourceIdColumn = typesTable.addColumn("sourceId"); auto &typesNameColumn = typesTable.addColumn("name"); typesTable.addColumn("accessSemantics"); - typesTable.addColumn("sourceId"); typesTable.addForeignKeyColumn("prototypeId", typesTable, Sqlite::ForeignKeyAction::NoAction, Sqlite::ForeignKeyAction::Restrict); typesTable.addColumn("prototypeNameId"); - typesTable.addUniqueIndex({moduleIdColumn, typesNameColumn}); + typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn}); typesTable.initialize(database); @@ -1709,20 +1858,18 @@ private: Sqlite::ForeignKeyAction::NoAction, Sqlite::Enforment::Deferred); auto &nameColumn = table.addColumn("name"); - auto &kindColumn = table.addColumn("kind"); auto &typeIdColumn = table.addColumn("typeId"); auto &majorVersionColumn = table.addColumn("majorVersion"); auto &minorVersionColumn = table.addColumn("minorVersion"); - table.addUniqueIndex({moduleIdColumn, nameColumn, kindColumn}, + table.addUniqueIndex({moduleIdColumn, nameColumn}, "majorVersion IS NULL AND minorVersion IS NULL"); - table.addUniqueIndex({moduleIdColumn, nameColumn, kindColumn, majorVersionColumn}, + table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn}, "majorVersion IS NOT NULL AND minorVersion IS NULL"); - table.addUniqueIndex( - {moduleIdColumn, nameColumn, kindColumn, majorVersionColumn, minorVersionColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); + table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn, minorVersionColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); - table.addIndex({typeIdColumn}, "kind=1"); + table.addIndex({typeIdColumn}); table.initialize(database); } @@ -1823,6 +1970,7 @@ private: Sqlite::Enforment::Deferred); auto &majorVersionColumn = table.addColumn("majorVersion"); auto &minorVersionColumn = table.addColumn("minorVersion"); + table.addColumn("kind"); table.addUniqueIndex({sourceIdColumn, moduleIdColumn}, "majorVersion IS NULL AND minorVersion IS NULL"); @@ -1856,18 +2004,18 @@ private: public: Database &database; Initializer initializer; + ModuleCache moduleCache{ModuleStorageAdapter{*this}}; ReadWriteStatement<1> upsertTypeStatement{ - "INSERT INTO types(moduleId, name, accessSemantics, sourceId) VALUES(?1, ?2, " - "?3, nullif(?4, -1)) ON CONFLICT DO UPDATE SET accessSemantics=excluded.accessSemantics, " - "sourceId=excluded.sourceId WHERE accessSemantics IS NOT excluded.accessSemantics OR " - "sourceId IS NOT excluded.sourceId RETURNING typeId", + "INSERT INTO types(sourceId, name, accessSemantics) VALUES(?1, ?2, ?3) ON CONFLICT DO " + "UPDATE SET accessSemantics=excluded.accessSemantics WHERE accessSemantics IS NOT " + "excluded.accessSemantics RETURNING typeId", database}; WriteStatement updatePrototypeStatement{ "UPDATE types SET prototypeId=?2, prototypeNameId=?3 WHERE typeId=?1 AND (prototypeId IS " "NOT ?2 OR prototypeNameId IS NOT ?3)", database}; mutable ReadStatement<1> selectTypeIdByExportedNameStatement{ - "SELECT typeId FROM exportedTypeNames WHERE name=?1 AND kind=1", database}; + "SELECT typeId FROM exportedTypeNames WHERE name=?1", database}; mutable ReadStatement<1> selectPrototypeIdStatement{ "WITH RECURSIVE " " typeSelection(typeId) AS (" @@ -1925,18 +2073,14 @@ public: "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database}; mutable ReadStatement<3> selectAllSourcesStatement{ "SELECT sourceName, sourceContextId, sourceId FROM sources", database}; - mutable ReadStatement<5> selectTypeByTypeIdStatement{ - "SELECT moduleId, name, (SELECT name FROM types WHERE typeId=outerTypes.prototypeId), " - "accessSemantics, ifnull(sourceId, -1) FROM types AS outerTypes WHERE typeId=?", + mutable ReadStatement<4> selectTypeByTypeIdStatement{ + "SELECT sourceId, name, prototypeId, accessSemantics FROM types WHERE typeId=?", database}; + mutable ReadStatement<4> selectExportedTypesByTypeIdStatement{ + "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM " + "exportedTypeNames WHERE typeId=?", database}; - mutable ReadStatement<3> selectExportedTypesByTypeIdStatement{ - "SELECT name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM exportedTypeNames " - "WHERE typeId=? AND kind=1", - database}; - mutable ReadStatement<6> selectTypesStatement{ - "SELECT moduleId, name, typeId, (SELECT name FROM types WHERE " - "typeId=t.prototypeId), accessSemantics, ifnull(sourceId, -1) FROM types AS " - "t", + mutable ReadStatement<5> selectTypesStatement{ + "SELECT sourceId, name, typeId, ifnull(prototypeId, -1), accessSemantics FROM types", database}; ReadStatement<1> selectNotUpdatedTypesInSourcesStatement{ "SELECT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN carray(?2))", @@ -1953,10 +2097,9 @@ public: "DELETE FROM signalDeclarations WHERE typeId=?", database}; WriteStatement deleteTypeStatement{"DELETE FROM types WHERE typeId=?", database}; mutable ReadStatement<4> selectPropertyDeclarationsByTypeIdStatement{ - "SELECT name, (SELECT name FROM types WHERE typeId=pd.propertyTypeId), propertyTraits, " - "(SELECT name FROM propertyDeclarations WHERE " - "propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM propertyDeclarations AS pd " - "WHERE typeId=?", + "SELECT name, nullif(propertyTypeId, -1), propertyTraits, (SELECT name FROM " + "propertyDeclarations WHERE propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM " + "propertyDeclarations AS pd WHERE typeId=?", database}; ReadStatement<6> selectPropertyDeclarationsForTypeIdStatement{ "SELECT name, propertyTraits, propertyTypeId, propertyImportedTypeNameId, " @@ -2081,25 +2224,18 @@ public: database}; WriteStatement deleteEnumerationDeclarationStatement{ "DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database}; - WriteStatement insertModuleStatement{"INSERT INTO modules(name, moduleId) VALUES(?1, ?2)", - database}; - WriteStatement updateModuleStatement{"UPDATE modules SET name=?2 WHERE moduleId=?1", database}; - WriteStatement deleteModuleStatement{"DELETE FROM modules WHERE moduleId=?", database}; mutable ReadStatement<1> selectModuleIdByNameStatement{ "SELECT moduleId FROM modules WHERE name=? LIMIT 1", database}; - mutable ReadStatement<2> selectModulesForIdsStatement{ - "SELECT name, moduleId FROM modules WHERE moduleId IN carray(?1) ORDER BY " - "moduleId", - database}; - mutable ReadStatement<2> selectAllModulesStatement{ - "SELECT name, moduleId FROM modules ORDER BY moduleId", database}; - mutable ReadStatement<1> selectTypeIdsForModuleIdStatement{ - "SELECT typeId FROM types WHERE moduleId=?", database}; - mutable ReadStatement<1> selectTypeIdByModuleIdAndNameStatement{ - "SELECT typeId FROM types WHERE moduleId=?1 and name=?2", database}; + mutable ReadWriteStatement<1> insertModuleNameStatement{ + "INSERT INTO modules(name) VALUES(?1) RETURNING moduleId", database}; + mutable ReadStatement<1> selectModuleNameStatement{ + "SELECT name FROM modules WHERE moduleId =?1", database}; + mutable ReadStatement<2> selectAllModulesStatement{"SELECT name, moduleId FROM modules", database}; + mutable ReadStatement<1> selectTypeIdBySourceIdAndNameStatement{ + "SELECT typeId FROM types WHERE sourceId=?1 and name=?2", database}; mutable ReadStatement<1> selectTypeIdByModuleIdsAndExportedNameStatement{ "SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND " - "name=?3 AND kind=1", + "name=?3", database}; mutable ReadStatement<5> selectDocumentImportForSourceIdStatement{ "SELECT importId, sourceId, moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) " @@ -2241,8 +2377,8 @@ public: WriteStatement deleteFileStatusStatement{"DELETE FROM fileStatuses WHERE sourceId=?1", database}; WriteStatement updateFileStatusStatement{ "UPDATE fileStatuses SET size=?2, lastModified=?3 WHERE sourceId=?1", database}; - ReadStatement<2> selectModuleAndTypeIdBySourceIdStatement{ - "SELECT moduleId, typeId FROM types WHERE sourceId=?", database}; + ReadStatement<1> selectTypeIdBySourceIdStatement{"SELECT typeId FROM types WHERE sourceId=?", + database}; mutable ReadStatement<1> selectImportedTypeNameIdStatement{ "SELECT importedTypeNameId FROM importedTypeNames WHERE kind=?1 AND importOrSourceId=?2 " "AND name=?3 LIMIT 1", @@ -2251,24 +2387,24 @@ public: "INSERT INTO importedTypeNames(kind, importOrSourceId, name) VALUES (?1, ?2, ?3) " "RETURNING importedTypeNameId", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndImportNameStatement{ - "SELECT importId FROM documentImports JOIN modules AS m USING(moduleId) WHERE sourceId=?1 " - "AND m.name=?2 AND majorVersion IS NULL AND minorVersion IS NULL LIMIT 1", + mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND majorVersion " + "IS NULL AND minorVersion IS NULL LIMIT 1", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndImportNameAndMajorVersionStatement{ - "SELECT importId FROM documentImports JOIN modules AS m USING(moduleId) WHERE sourceId=?1 " - "AND m.name=?2 AND majorVersion=?3 AND minorVersion IS NULL LIMIT 1", + mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " + "majorVersion=?3 AND minorVersion IS NULL LIMIT 1", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndImportNameAndVersionStatement{ - "SELECT importId FROM documentImports JOIN modules AS m USING(moduleId) WHERE sourceId=?1 " - "AND m.name=?2 AND majorVersion=?3 AND minorVersion=?4 LIMIT 1", + mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdAndVersionStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " + "majorVersion=?3 AND minorVersion=?4 LIMIT 1", database}; mutable ReadStatement<1> selectKindFromImportedTypeNamesStatement{ "SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database}; mutable ReadStatement<1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{ "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " "importOrSourceId=importId JOIN exportedTypeNames AS etn USING(moduleId) WHERE " - "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND etn.kind=1 AND " + "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND " "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS " "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, " "etn.minorVersion DESC NULLS FIRST LIMIT 1", @@ -2276,39 +2412,29 @@ public: mutable ReadStatement<1> selectTypeIdForImportedTypeNameNamesStatement{ "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " "importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE " - "itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND etn.kind=1 AND " + "itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND " "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS " "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, " "etn.minorVersion DESC NULLS FIRST LIMIT 1", database}; - mutable ReadStatement<1> selectTypeIdForNativeTypeNameNamesStatement{ - "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " - "importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE itn.kind=0 " - "AND importedTypeNameId=?1 AND itn.name=etn.name AND etn.kind=0 LIMIT 1", - database}; WriteStatement deleteAllSourcesStatement{"DELETE FROM sources", database}; WriteStatement deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database}; - mutable ReadStatement<6> selectExportedTypesForTypeIdStatement{ - "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, " - "exportedTypeNameId FROM exportedTypeNames WHERE typeId IN carray(?1, ?2, 'int64') AND " - "kind=1 ORDER BY moduleId, name, majorVersion, minorVersion", + mutable ReadStatement<6> selectExportedTypesForSourceIdsStatement{ + "SELECT moduleId, etn.name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, " + "exportedTypeNameId FROM exportedTypeNames AS etn JOIN types USING(typeId) WHERE sourceId " + "IN carray(?1) OR typeId in carray(?2) ORDER BY moduleId, etn.name, majorVersion, " + "minorVersion", database}; - WriteStatement upsertExportedTypeNamesWithVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, kind, majorVersion, minorVersion, typeId) " - "VALUES(?1, ?2, ?3, ?4, ?5, ?6) ON CONFLICT DO UPDATE SET typeId=excluded.typeId", + WriteStatement insertExportedTypeNamesWithVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, minorVersion, typeId) " + "VALUES(?1, ?2, ?3, ?4, ?5)", database}; - WriteStatement upsertExportedTypeNamesWithMajorVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, kind, majorVersion, typeId) " - "VALUES(?1, ?2, ?3, ?4, ?5) ON CONFLICT DO UPDATE SET typeId=excluded.typeId", - database}; - WriteStatement upsertExportedTypeNamesWithoutVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, kind, typeId) VALUES(?1, ?2, ?3, ?4) ON " - "CONFLICT DO UPDATE SET typeId=excluded.typeId", - database}; - WriteStatement upsertExportedTypeNameStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, kind, typeId) VALUES(?1, ?2, ?3, ?4) ON " - "CONFLICT DO UPDATE SET typeId=excluded.typeId WHERE typeId IS NOT excluded.typeId", + WriteStatement insertExportedTypeNamesWithMajorVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, typeId) " + "VALUES(?1, ?2, ?3, ?4)", database}; + WriteStatement insertExportedTypeNamesWithoutVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, typeId) VALUES(?1, ?2, ?3)", database}; WriteStatement deleteExportedTypeNameStatement{ "DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database}; WriteStatement updateExportedTypeNameTypeIdStatement{ diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h index 302a1801a2d..4eaa0527d23 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h @@ -33,13 +33,14 @@ namespace QmlDesigner { class ProjectStorageInterface { public: - virtual void synchronize(Storage::Modules modules, - Storage::Imports imports, + virtual void synchronize(Storage::Imports imports, Storage::Types types, SourceIds sourceIds, FileStatuses fileStatuses) = 0; + virtual ModuleId moduleId(Utils::SmallStringView name) = 0; + virtual FileStatus fetchFileStatus(SourceId sourceId) const = 0; virtual SourceIds fetchSourceDependencieIds(SourceId sourceId) const = 0; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index 592f510c8d2..ffbfe7364cb 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -121,38 +121,6 @@ public: VersionNumber minor; }; -class Module -{ -public: - explicit Module() = default; - - explicit Module(Utils::SmallStringView name, SourceId sourceId = SourceId{}) - : name{name} - , sourceId{sourceId} - {} - - explicit Module(QStringView name, SourceId sourceId = SourceId{}) - : name{name} - , sourceId{sourceId} - {} - - explicit Module(Utils::SmallStringView name, int sourceId) - : name{name} - , sourceId{sourceId} - {} - - friend bool operator==(const Module &first, const Module &second) - { - return first.name == second.name; - } - -public: - Utils::PathString name; - SourceId sourceId; -}; - -using Modules = std::vector; - enum class IsQualified : int { No, Yes }; inline int operator-(IsQualified first, IsQualified second) @@ -172,41 +140,29 @@ class Import public: explicit Import() = default; - explicit Import(Utils::SmallStringView name, - Version version, - SourceId sourceId, - ImportKind kind = ImportKind::Module) - : name{name} - , version{version} - , sourceId{sourceId} - , kind{kind} - {} - - explicit Import(Version version, ModuleId moduleId, SourceId sourceId) + explicit Import(ModuleId moduleId, Version version, SourceId sourceId) : version{version} , moduleId{moduleId} , sourceId{sourceId} {} - explicit Import(Utils::SmallStringView name, int majorVersion, int minorVersion, int sourceId) - : name{name} + explicit Import(int moduleId, int majorVersion, int minorVersion, int sourceId) + : moduleId{moduleId} , version{majorVersion, minorVersion} , sourceId{sourceId} {} friend bool operator==(const Import &first, const Import &second) { - return first.name == second.name && first.version == second.version - && first.sourceId == second.sourceId && first.moduleId.id == second.moduleId.id; + return first.moduleId == second.moduleId && first.version == second.version + && first.sourceId == second.sourceId; } public: - Utils::SmallString name; Version version; ModuleId moduleId; SourceId sourceId; Utils::SmallString aliasName; - ImportKind kind = ImportKind::Module; }; using Imports = std::vector; @@ -296,9 +252,10 @@ public: , moduleId{moduleId} {} - explicit ExportedType(Utils::SmallStringView name, int majorVersion, int minorVersion) + explicit ExportedType(int moduleId, Utils::SmallStringView name, int majorVersion, int minorVersion) : name{name} , version{majorVersion, minorVersion} + , moduleId{moduleId} {} friend bool operator==(const ExportedType &first, const ExportedType &second) @@ -576,6 +533,15 @@ public: , kind{PropertyKind::Property} {} + explicit PropertyDeclaration(Utils::SmallStringView name, + TypeId propertyTypeId, + PropertyDeclarationTraits traits) + : name{name} + , traits{traits} + , propertyTypeId{propertyTypeId} + , kind{PropertyKind::Property} + {} + explicit PropertyDeclaration(Utils::SmallStringView name, ImportedTypeName typeName, PropertyDeclarationTraits traits, @@ -588,13 +554,24 @@ public: {} explicit PropertyDeclaration(Utils::SmallStringView name, - Utils::SmallStringView typeName, + TypeId propetyTypeId, + PropertyDeclarationTraits traits, + Utils::SmallStringView aliasPropertyName) + : name{name} + , aliasPropertyName{aliasPropertyName} + , traits{traits} + , propertyTypeId{propertyTypeId} + , kind{PropertyKind::Property} + {} + + explicit PropertyDeclaration(Utils::SmallStringView name, + long long propertyTypeId, int traits, Utils::SmallStringView aliasPropertyName) : name{name} - , typeName{NativeType{typeName}} , aliasPropertyName{aliasPropertyName} , traits{static_cast(traits)} + , propertyTypeId{propertyTypeId} , kind{PropertyKind::Property} {} @@ -619,6 +596,7 @@ public: ImportedTypeName typeName; Utils::SmallString aliasPropertyName; PropertyDeclarationTraits traits = {}; + TypeId propertyTypeId; TypeId typeId; PropertyKind kind = PropertyKind::Property; }; @@ -657,8 +635,7 @@ class Type { public: explicit Type() = default; - explicit Type(ModuleId moduleId, - Utils::SmallStringView typeName, + explicit Type(Utils::SmallStringView typeName, ImportedTypeName prototype, TypeAccessSemantics accessSemantics, SourceId sourceId, @@ -677,12 +654,20 @@ public: , enumerationDeclarations{std::move(enumerationDeclarations)} , accessSemantics{accessSemantics} , sourceId{sourceId} - , moduleId{moduleId} , changeLevel{changeLevel} {} - explicit Type(ModuleId moduleId, - Utils::SmallStringView typeName, + explicit Type(Utils::SmallStringView typeName, + TypeId prototypeId, + TypeAccessSemantics accessSemantics, + SourceId sourceId) + : typeName{typeName} + , accessSemantics{accessSemantics} + , sourceId{sourceId} + , prototypeId{prototypeId} + {} + + explicit Type(Utils::SmallStringView typeName, Utils::SmallStringView prototype, int accessSemantics, int sourceId) @@ -690,22 +675,19 @@ public: , prototype{NativeType{prototype}} , accessSemantics{static_cast(accessSemantics)} , sourceId{sourceId} - , moduleId{moduleId} {} - explicit Type(int moduleId, + explicit Type(int sourceId, Utils::SmallStringView typeName, long long typeId, - Utils::SmallStringView prototype, - int accessSemantics, - int sourceId) + long long prototypeId, + int accessSemantics) : typeName{typeName} - , prototype{NativeType{prototype}} , accessSemantics{static_cast(accessSemantics)} , sourceId{sourceId} , typeId{typeId} - , moduleId{moduleId} + , prototypeId{prototypeId} {} friend bool operator==(const Type &first, const Type &second) noexcept @@ -715,7 +697,6 @@ public: && first.propertyDeclarations == second.propertyDeclarations && first.functionDeclarations == second.functionDeclarations && first.signalDeclarations == second.signalDeclarations - && first.moduleId == second.moduleId && first.sourceId == second.sourceId && first.sourceId == second.sourceId; } @@ -730,28 +711,10 @@ public: TypeAccessSemantics accessSemantics = TypeAccessSemantics::None; SourceId sourceId; TypeId typeId; - ModuleId moduleId; + TypeId prototypeId; ChangeLevel changeLevel = ChangeLevel::Full; }; using Types = std::vector; -class ModuleView -{ -public: - explicit ModuleView(Utils::SmallStringView name, int sourceId) - : name{name} - , sourceId{sourceId} - {} - - friend bool operator==(const ModuleView &first, const ModuleView &second) - { - return first.name == second.name && first.sourceId == second.sourceId; - } - -public: - Utils::SmallStringView name; - SourceId sourceId; -}; - } // namespace QmlDesigner::Storage diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp index a16859ae230..5a23b699448 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp @@ -52,7 +52,6 @@ ComponentReferences createComponentReferences(const QMultiHash &qmlImports, SourceId sourceId, SourceContextId sourceContextId, - QmlDocumentParser::PathCache &pathCache) + QmlDocumentParser::PathCache &pathCache, + QmlDocumentParser::ProjectStorage &storage) { for (const QmlDom::Import &qmlImport : qmlImports) { if (qmlImport.uri == u"file://.") { - SourceId directorySourceId = pathCache.sourceId(sourceContextId, "."); - imports.emplace_back(Storage::Version{}, ModuleId{&directorySourceId}, sourceId); + auto moduleId = storage.moduleId(pathCache.sourceContextPath(sourceContextId)); + imports.emplace_back(moduleId, Storage::Version{}, sourceId); } else if (qmlImport.uri.startsWith(u"file://")) { - SourceId uriSourceId = pathCache.sourceId(sourceContextId, convertUri(qmlImport.uri)); - imports.emplace_back(Storage::Version{}, ModuleId{&uriSourceId}, sourceId); + auto moduleId = storage.moduleId(convertUri(qmlImport.uri)); + imports.emplace_back(moduleId, Storage::Version{}, sourceId); } else { - imports.emplace_back(Utils::SmallString{qmlImport.uri}, - convertVersion(qmlImport.version), - sourceId); + auto moduleId = storage.moduleId(Utils::SmallString{qmlImport.uri}); + imports.emplace_back(moduleId, convertVersion(qmlImport.version), sourceId); } } } @@ -185,7 +185,7 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent, type.prototype = Storage::ImportedType{Utils::SmallString{qmlObject.name()}}; - addImports(imports, qmlFile->imports(), sourceId, sourceContextId, m_pathCache); + addImports(imports, qmlFile->imports(), sourceId, sourceContextId, m_pathCache, m_storage); addPropertyDeclarations(type, qmlObject); addFunctionAndSignalDeclarations(type, qmlObject); diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h index cc272dd4227..e2dd2434058 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h @@ -43,11 +43,12 @@ class SourcePathCache; class QmlDocumentParser { public: - using PathCache = QmlDesigner::SourcePathCache, - NonLockingMutex>; + using ProjectStorage = QmlDesigner::ProjectStorage; + using PathCache = QmlDesigner::SourcePathCache; - QmlDocumentParser(PathCache &pathCache) + QmlDocumentParser(PathCache &pathCache, ProjectStorage &storage) : m_pathCache{pathCache} + , m_storage{storage} {} virtual Storage::Type parse(const QString &sourceContent, @@ -57,5 +58,6 @@ public: private: PathCache &m_pathCache; + ProjectStorage &m_storage; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp index ed9352cd474..e3942653218 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp @@ -45,15 +45,20 @@ namespace QmlDom = QQmlJS::Dom; namespace { void addType(const QQmlJSScope::Ptr &object, Storage::Types &types) {} -Storage::Import createImport(const QString &dependency, SourceId sourceId) +void appendImports(Storage::Imports &imports, + const QString &dependency, + SourceId sourceId, + QmlTypesParser::ProjectStorage &storage) { - Storage::Import import; - import.kind = Storage::ImportKind::QmlTypesDependency; - import.sourceId = sourceId; auto spaceFound = std::find_if(dependency.begin(), dependency.end(), [](QChar c) { return c.isSpace(); }); - import.name = Utils::SmallString{QStringView(dependency.begin(), spaceFound)}; + + Utils::PathString moduleName{QStringView(dependency.begin(), spaceFound)}; + ModuleId moduleId = storage.moduleId(moduleName); + + moduleName.append("-cppnative"); + ModuleId cppModuleId = storage.moduleId(moduleName); auto majorVersionFound = std::find_if(spaceFound, dependency.end(), [](QChar c) { return c.isDigit(); @@ -61,33 +66,39 @@ Storage::Import createImport(const QString &dependency, SourceId sourceId) auto majorVersionEnd = std::find_if(majorVersionFound, dependency.end(), [](QChar c) { return !c.isDigit(); }); + + Storage::Version version; + QStringView majorVersionString(majorVersionFound, majorVersionEnd); - if (majorVersionString.isEmpty()) - return import; - import.version.major.value = majorVersionString.toInt(); + if (!majorVersionString.isEmpty()) { + version.major.value = majorVersionString.toInt(); - auto minorVersionFound = std::find_if(majorVersionEnd, dependency.end(), [](QChar c) { - return c.isDigit(); - }); - auto minorVersionEnd = std::find_if(minorVersionFound, dependency.end(), [](QChar c) { - return !c.isDigit(); - }); - QStringView minorVersionString(minorVersionFound, minorVersionEnd); - if (minorVersionString.isEmpty()) - return import; - import.version.minor.value = QStringView(minorVersionFound, minorVersionEnd).toInt(); - - return import; -} - -void addImports(Storage::Imports &imports, SourceId sourceId, const QStringList &dependencies) -{ - for (const QString &dependency : dependencies) { - imports.push_back(createImport(dependency, sourceId)); + auto minorVersionFound = std::find_if(majorVersionEnd, dependency.end(), [](QChar c) { + return c.isDigit(); + }); + auto minorVersionEnd = std::find_if(minorVersionFound, dependency.end(), [](QChar c) { + return !c.isDigit(); + }); + QStringView minorVersionString(minorVersionFound, minorVersionEnd); + if (!minorVersionString.isEmpty()) + version.minor.value = QStringView(minorVersionFound, minorVersionEnd).toInt(); } - imports.emplace_back("QML", Storage::Version{}, sourceId, Storage::ImportKind::QmlTypesDependency); - imports.emplace_back("QtQml", Storage::Version{}, sourceId, Storage::ImportKind::QmlTypesDependency); + imports.emplace_back(moduleId, version, sourceId); + imports.emplace_back(cppModuleId, version, sourceId); +} + +void addImports(Storage::Imports &imports, + SourceId sourceId, + const QStringList &dependencies, + QmlTypesParser::ProjectStorage &storage) +{ + for (const QString &dependency : dependencies) + appendImports(imports, dependency, sourceId, storage); + + imports.emplace_back(storage.moduleId("QML"), Storage::Version{}, sourceId); + imports.emplace_back(storage.moduleId("QtQml"), Storage::Version{}, sourceId); + imports.emplace_back(storage.moduleId("QtQml-cppnative"), Storage::Version{}, sourceId); } Storage::TypeAccessSemantics createTypeAccessSemantics(QQmlJSScope::AccessSemantics accessSematics) @@ -249,8 +260,7 @@ Storage::EnumerationDeclarations createEnumeration(const QHash, - NonLockingMutex>; + using ProjectStorage = QmlDesigner::ProjectStorage; + using PathCache = QmlDesigner::SourcePathCache; - QmlTypesParser(PathCache &pathCache) + QmlTypesParser(PathCache &pathCache, ProjectStorage &storage) : m_pathCache{pathCache} + , m_storage{storage} {} void parse(const QString &sourceContent, @@ -58,5 +59,6 @@ public: private: PathCache &m_pathCache; + ProjectStorage &m_storage; }; } // namespace QmlDesigner diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 85ff406f953..3123ffcf1d7 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -1095,8 +1095,8 @@ std::ostream &operator<<(std::ostream &out, Version version) std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType) { - return out << "(\"" << exportedType.name << "\"" - << ", " << exportedType.version << ")"; + return out << "(\"" << exportedType.name << "\"," << exportedType.moduleId << ", " + << exportedType.version << ")"; } std::ostream &operator<<(std::ostream &out, const NativeType &nativeType) @@ -1116,10 +1116,9 @@ std::ostream &operator<<(std::ostream &out, const QualifiedImportedType &importe std::ostream &operator<<(std::ostream &out, const Type &type) { using Utils::operator<<; - return out << "(moduleId: " << type.moduleId << ", typename: \"" << type.typeName - << "\", prototype: " << type.prototype << ", " << type.accessSemantics - << ", source: " << type.sourceId << ", exports: " << type.exportedTypes - << ", properties: " << type.propertyDeclarations + return out << "( typename: \"" << type.typeName << "\", prototype: " << type.prototype << ", " + << type.prototypeId << ", " << type.accessSemantics << ", source: " << type.sourceId + << ", exports: " << type.exportedTypes << ", properties: " << type.propertyDeclarations << ", functions: " << type.functionDeclarations << ", signals: " << type.signalDeclarations << ")"; } @@ -1127,9 +1126,10 @@ std::ostream &operator<<(std::ostream &out, const Type &type) std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyDeclaration) { using Utils::operator<<; - return out << "(\"" << propertyDeclaration.name << "\", \"" << propertyDeclaration.typeName - << "\", " << propertyDeclaration.traits << ", " << propertyDeclaration.typeId - << ", \"" << propertyDeclaration.aliasPropertyName << "\")"; + return out << "(\"" << propertyDeclaration.name << "\", " << propertyDeclaration.typeName + << ", " << propertyDeclaration.typeId << ", " << propertyDeclaration.traits << ", " + << propertyDeclaration.typeId << ", \"" << propertyDeclaration.aliasPropertyName + << "\")"; } std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits) @@ -1186,11 +1186,6 @@ std::ostream &operator<<(std::ostream &out, const EnumerationDeclaration &enumer << enumerationDeclaration.enumeratorDeclarations << ")"; } -std::ostream &operator<<(std::ostream &out, const Module &module) -{ - return out << "(" << module.name << ", " << module.sourceId << ")"; -} - std::ostream &operator<<(std::ostream &out, const ImportKind &importKind) { return out << importKindToText(importKind); @@ -1198,8 +1193,7 @@ std::ostream &operator<<(std::ostream &out, const ImportKind &importKind) std::ostream &operator<<(std::ostream &out, const Import &import) { - return out << "(" << import.name << ", " << import.version << ", " << import.sourceId << ", " - << import.moduleId << ", " << import.kind << ")"; + return out << "(" << import.moduleId << ", " << import.version << ", " << import.sourceId << ")"; } } // namespace Storage diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 5b8cb51e8e3..074fada6d91 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -260,8 +260,6 @@ class ParameterDeclaration; class SignalDeclaration; class EnumerationDeclaration; class EnumeratorDeclaration; -class Module; -class ModuleDependency; enum class ImportKind : char; class Import; enum class IsQualified : int; @@ -281,8 +279,6 @@ std::ostream &operator<<(std::ostream &out, const ParameterDeclaration ¶mete std::ostream &operator<<(std::ostream &out, const SignalDeclaration &signalDeclaration); std::ostream &operator<<(std::ostream &out, const EnumerationDeclaration &enumerationDeclaration); std::ostream &operator<<(std::ostream &out, const EnumeratorDeclaration &enumeratorDeclaration); -std::ostream &operator<<(std::ostream &out, const Module &module); -std::ostream &operator<<(std::ostream &out, const ModuleDependency &module); std::ostream &operator<<(std::ostream &out, const ImportKind &importKind); std::ostream &operator<<(std::ostream &out, const Import &import); std::ostream &operator<<(std::ostream &out, IsQualified isQualified); diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp index da71b36d318..bd6fda06bc3 100644 --- a/tests/unit/unittest/projectstorage-test.cpp +++ b/tests/unit/unittest/projectstorage-test.cpp @@ -83,34 +83,18 @@ MATCHER_P2(IsSourceNameAndSourceContextId, && sourceNameAndSourceContextId.sourceContextId == id; } -MATCHER_P5(IsStorageType, - moduleId, - typeName, - prototype, - accessSemantics, +MATCHER_P4(IsStorageType, sourceId, - std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::Type{moduleId, typeName, prototype, accessSemantics, sourceId})) -{ - const Storage::Type &type = arg; - - return type.moduleId == moduleId && type.typeName == typeName - && type.accessSemantics == accessSemantics && type.sourceId == sourceId - && Storage::ImportedTypeName{prototype} == type.prototype; -} - -MATCHER_P4(IsStorageTypeWithInvalidSourceId, - moduleId, typeName, - prototype, + prototypeId, accessSemantics, std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::Type{moduleId, typeName, prototype, accessSemantics, SourceId{}})) + + PrintToString(Storage::Type{typeName, prototypeId, accessSemantics, sourceId})) { const Storage::Type &type = arg; - return type.moduleId == moduleId && type.typeName == typeName && type.prototype == prototype - && type.accessSemantics == accessSemantics && !type.sourceId.isValid(); + return type.sourceId == sourceId && type.typeName == typeName + && type.accessSemantics == accessSemantics && prototypeId.id == type.prototypeId.id; } MATCHER_P(IsExportedType, @@ -122,6 +106,17 @@ MATCHER_P(IsExportedType, return type.name == name; } +MATCHER_P2(IsExportedType, + moduleId, + name, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::ExportedType{moduleId, name})) +{ + const Storage::ExportedType &type = arg; + + return type.moduleId == moduleId && type.name == name; +} + MATCHER_P3(IsExportedType, name, majorVersion, @@ -135,56 +130,51 @@ MATCHER_P3(IsExportedType, return type.name == name && type.version == Storage::Version{majorVersion, minorVersion}; } +MATCHER_P4(IsExportedType, + moduleId, + name, + majorVersion, + minorVersion, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::ExportedType{moduleId, + name, + Storage::Version{majorVersion, minorVersion}})) +{ + const Storage::ExportedType &type = arg; + + return type.moduleId == moduleId && type.name == name + && type.version == Storage::Version{majorVersion, minorVersion}; +} + MATCHER_P3(IsPropertyDeclaration, name, - typeName, + propertyTypeId, traits, std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::PropertyDeclaration{name, typeName, traits})) + + PrintToString(Storage::PropertyDeclaration{name, propertyTypeId, traits})) { const Storage::PropertyDeclaration &propertyDeclaration = arg; - return propertyDeclaration.name == name - && Storage::ImportedTypeName{typeName} == propertyDeclaration.typeName + return propertyDeclaration.name == name && propertyTypeId == propertyDeclaration.propertyTypeId && propertyDeclaration.traits == traits; } MATCHER_P4(IsPropertyDeclaration, name, - typeName, + propertyTypeId, traits, aliasPropertyName, std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::PropertyDeclaration(name, typeName, traits, aliasPropertyName))) + + PrintToString( + Storage::PropertyDeclaration{name, propertyTypeId, traits, aliasPropertyName})) { const Storage::PropertyDeclaration &propertyDeclaration = arg; - return propertyDeclaration.name == name - && Utils::visit([&](auto &&v) -> bool { return v.name == typeName.name; }, - propertyDeclaration.typeName) + return propertyDeclaration.name == name && propertyTypeId == propertyDeclaration.propertyTypeId && propertyDeclaration.aliasPropertyName == aliasPropertyName && propertyDeclaration.traits == traits; } -MATCHER_P(IsModule, - name, - std::string(negation ? "isn't " : "is ") + PrintToString(Storage::Module{name})) -{ - const Storage::Module &module = arg; - - return module.name == name; -} - -MATCHER_P2(IsModule, - name, - sourceId, - std::string(negation ? "isn't " : "is ") + PrintToString(Storage::Module{name, sourceId})) -{ - const Storage::Module &module = arg; - - return module.name == name; -} - class ProjectStorage : public testing::Test { protected: @@ -214,25 +204,31 @@ protected: auto createTypes() { - imports.emplace_back("Qml", Storage::Version{}, sourceId1); - imports.emplace_back("Qml", Storage::Version{}, sourceId2); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId1); + imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1); + imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1); + imports.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId1); + imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId2); + imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId2); - importsSourceId1.emplace_back("Qml", Storage::Version{}, sourceId1); - importsSourceId1.emplace_back("QtQuick", Storage::Version{}, sourceId1); + importsSourceId1.emplace_back(qmlModuleId, Storage::Version{}, sourceId1); + importsSourceId1.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1); + importsSourceId1.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1); + importsSourceId1.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId1); - importsSourceId2.emplace_back("Qml", Storage::Version{}, sourceId2); + importsSourceId2.emplace_back(qmlModuleId, Storage::Version{}, sourceId2); + importsSourceId2.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId2); return Storage::Types{ Storage::Type{ - qtQuickModuleId, "QQuickItem", - Storage::NativeType{"QObject"}, + Storage::ImportedType{"QObject"}, TypeAccessSemantics::Reference, sourceId1, - {Storage::ExportedType{"Item"}}, + {Storage::ExportedType{qtQuickModuleId, "Item"}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}, {Storage::PropertyDeclaration{"data", - Storage::NativeType{"QObject"}, + Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsList}, Storage::PropertyDeclaration{"children", Storage::ImportedType{"Item"}, @@ -261,48 +257,48 @@ protected: Storage::EnumerationDeclaration{"Type", {Storage::EnumeratorDeclaration{"Foo"}, Storage::EnumeratorDeclaration{"Poo", 12}}}}}, - Storage::Type{qmlModuleId, - "QObject", - Storage::NativeType{}, + Storage::Type{"QObject", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Object", Storage::Version{2}}, - Storage::ExportedType{"Obj", Storage::Version{2}}}}}; + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2}}, + Storage::ExportedType{qmlNativeModuleId, "QObject"}}}}; } auto createVersionedTypes() { - return Storage::Types{Storage::Type{qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Object", Storage::Version{1}}, - Storage::ExportedType{"Obj", Storage::Version{1, 2}}, - Storage::ExportedType{"BuiltInObj", Storage::Version{}}}}, - Storage::Type{qmlModuleId, - "QObject2", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Object", Storage::Version{2, 0}}, - Storage::ExportedType{"Obj", Storage::Version{2, 3}}}}, - Storage::Type{qmlModuleId, - "QObject3", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Object", Storage::Version{2, 11}}, - Storage::ExportedType{"Obj", Storage::Version{2, 11}}}}, - Storage::Type{qmlModuleId, - "QObject4", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Object", Storage::Version{3, 4}}, - Storage::ExportedType{"Obj", Storage::Version{3, 4}}, - Storage::ExportedType{"BuiltInObj", - Storage::Version{3, 4}}}}}; + return Storage::Types{ + Storage::Type{"QObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{1}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{1, 2}}, + Storage::ExportedType{qmlModuleId, "BuiltInObj"}, + Storage::ExportedType{qmlNativeModuleId, "QObject"}}}, + Storage::Type{"QObject2", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2, 0}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2, 3}}, + Storage::ExportedType{qmlNativeModuleId, "QObject2"}}}, + Storage::Type{"QObject3", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2, 11}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2, 11}}, + Storage::ExportedType{qmlNativeModuleId, "QObject3"}}}, + Storage::Type{"QObject4", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{3, 4}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{3, 4}}, + Storage::ExportedType{qmlModuleId, "BuiltInObj", Storage::Version{3, 4}}, + Storage::ExportedType{qmlNativeModuleId, "QObject4"}}}}; } auto createTypesWithExportedTypeNamesOnly() @@ -319,48 +315,53 @@ protected: { auto types = createTypes(); - imports.emplace_back("Qml", Storage::Version{}, sourceId3); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3); + imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + imports.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId3); - imports.emplace_back("Qml", Storage::Version{}, sourceId4); - imports.emplace_back("/path/to", Storage::Version{}, sourceId4); + imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4); + imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId4); - importsSourceId3.emplace_back("Qml", Storage::Version{}, sourceId3); - importsSourceId3.emplace_back("QtQuick", Storage::Version{}, sourceId3); + importsSourceId3.emplace_back(qmlModuleId, Storage::Version{}, sourceId3); + importsSourceId3.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3); + importsSourceId3.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + importsSourceId3.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId3); - importsSourceId4.emplace_back("Qml", Storage::Version{}, sourceId4); - importsSourceId4.emplace_back("/path/to", Storage::Version{}, sourceId4); + importsSourceId4.emplace_back(qmlModuleId, Storage::Version{}, sourceId4); + importsSourceId4.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); + importsSourceId4.emplace_back(pathToModuleId, Storage::Version{}, sourceId4); types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QObject"}, + Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsList}); - types.push_back(Storage::Type{qtQuickModuleId, - "QAliasItem", + types.push_back(Storage::Type{"QAliasItem", Storage::ImportedType{"Item"}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"AliasItem"}}}); + {Storage::ExportedType{qtQuickModuleId, "AliasItem"}, + Storage::ExportedType{qtQuickNativeModuleId, "QAliasItem"}}}); types.back().propertyDeclarations.push_back( Storage::PropertyDeclaration{"data", - Storage::NativeType{"QObject"}, + Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsList}); types.back().propertyDeclarations.push_back( Storage::PropertyDeclaration{"items", Storage::ImportedType{"Item"}, "children"}); types.back().propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"Item"}, "objects"}); - types.push_back( - Storage::Type{pathToModuleId, - "QObject2", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId4, - {Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}}); + types.push_back(Storage::Type{"QObject2", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId4, + {Storage::ExportedType{pathToModuleId, "Object2"}, + Storage::ExportedType{pathToModuleId, "Obj2"}}}); types[3].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QObject"}, + Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsList}); return types; @@ -368,16 +369,16 @@ protected: auto createTypesWithRecursiveAliases() { - imports.emplace_back("Qml", Storage::Version{}, sourceId5); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId5); + imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId5); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5); auto types = createTypesWithAliases(); - types.push_back(Storage::Type{qtQuickModuleId, - "QAliasItem2", + types.push_back(Storage::Type{"QAliasItem2", Storage::ImportedType{"Object"}, TypeAccessSemantics::Reference, sourceId5, - {Storage::ExportedType{"AliasItem2"}}}); + {Storage::ExportedType{qtQuickModuleId, "AliasItem2"}, + Storage::ExportedType{qtQuickNativeModuleId, "QAliasItem2"}}}); types.back().propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"AliasItem"}, "objects"}); @@ -388,38 +389,19 @@ protected: auto createTypesWithAliases2() { auto types = createTypesWithAliases(); - types[2].prototype = Storage::NativeType{"QObject"}; + types[2].prototype = Storage::ImportedType{"Object"}; types[2].propertyDeclarations.erase(std::next(types[2].propertyDeclarations.begin())); return types; } - Storage::Modules createModules() - { - return Storage::Modules{Storage::Module{"Qml", qmlModuleSourceId}, - Storage::Module{"QtQuick", qtQuickModuleSourceId}, - Storage::Module{"/path/to", pathToModuleSourceId}}; - } - Storage::Imports createImports(SourceId sourceId) { - return Storage::Imports{Storage::Import{"Qml", Storage::Version{2}, sourceId}, - Storage::Import{"QtQuick", Storage::Version{}, sourceId}, - Storage::Import{"/path/to", Storage::Version{}, sourceId}}; - } - - static Storage::Imports createImports(const SourceIds &sourceIds) - { - Storage::Imports imports; - imports.reserve(3 * sourceIds.size()); - - for (SourceId sourceId : sourceIds) { - imports.emplace_back("Qml", Storage::Version{2}, sourceId); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId); - imports.emplace_back("/path/to", Storage::Version{}, sourceId); - } - - return imports; + return Storage::Imports{Storage::Import{qmlModuleId, Storage::Version{2}, sourceId}, + Storage::Import{qmlNativeModuleId, Storage::Version{}, sourceId}, + Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId}, + Storage::Import{qtQuickNativeModuleId, Storage::Version{}, sourceId}, + Storage::Import{pathToModuleId, Storage::Version{}, sourceId}}; } template @@ -428,9 +410,14 @@ protected: return FileStatuses(range.begin(), range.end()); } + TypeId fetchTypeId(SourceId sourceId, Utils::SmallStringView name) + { + return storage.fetchTypeIdByName(sourceId, name); + } + protected: Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; - //Sqlite::Database database{TESTDATA_DIR "/aaaa.db", Sqlite::JournalMode::Wal}; + //Sqlite::Database database{TESTDATA_DIR "/aaaaa.db", Sqlite::JournalMode::Wal}; QmlDesigner::ProjectStorage storage{database, database.isInitialized()}; QmlDesigner::SourcePathCache> sourcePathCache{ storage}; @@ -455,10 +442,11 @@ protected: SourceId pathToModuleSourceId{sourcePathCache.sourceId(modulePath3)}; SourceId moduleSourceId4{sourcePathCache.sourceId(modulePath4)}; SourceId moduleSourceId5{sourcePathCache.sourceId(modulePath5)}; - Storage::Modules modules{createModules()}; - ModuleId qmlModuleId{&qmlModuleSourceId}; - ModuleId qtQuickModuleId{&qtQuickModuleSourceId}; - ModuleId pathToModuleId{&pathToModuleSourceId}; + ModuleId qmlModuleId{storage.moduleId("Qml")}; + ModuleId qmlNativeModuleId{storage.moduleId("Qml-cppnative")}; + ModuleId qtQuickModuleId{storage.moduleId("QtQuick")}; + ModuleId qtQuickNativeModuleId{storage.moduleId("QtQuick-cppnative")}; + ModuleId pathToModuleId{storage.moduleId("/path/to")}; Storage::Imports imports; Storage::Imports importsSourceId1; Storage::Imports importsSourceId2; @@ -674,28 +662,26 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypes) Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); } TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExportedPrototypeName) @@ -704,28 +690,26 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExportedPrototypeName) types[0].prototype = Storage::ImportedType{"Object"}; storage.synchronize( - modules, importsSourceId1, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); } TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesThrowsWithWrongPrototypeName) @@ -733,8 +717,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesThrowsWithWrongPrototypeName) Storage::Types types{createTypes()}; types[0].prototype = Storage::ImportedType{"Objec"}; - ASSERT_THROW(storage.synchronize(modules, - imports, + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -748,80 +731,55 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesThrowsWithWrongPrototypeName) TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithMissingModuleAndPrototypeName) { Storage::Types types{createTypes()}; - types.push_back(Storage::Type{pathToModuleId, - "QObject2", - Storage::NativeType{}, + types.push_back(Storage::Type{"QObject2", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}}); + {Storage::ExportedType{ModuleId{22}, "Object2"}, + Storage::ExportedType{pathToModuleId, "Obj2"}}}); storage.synchronize( - modules, imports, {}, {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[1].prototype = Storage::ImportedType{"Object2"}; - ASSERT_THROW(storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } -TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithMissingModule) -{ - Storage::Types types{createTypes()}; - storage.synchronize(modules, - imports, - {}, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - - ASSERT_THROW(storage.synchronize({}, - imports, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::ModuleDoesNotExists); -} - TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesReverseOrder) { Storage::Types types{createTypes()}; std::reverse(types.begin(), types.end()); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); } TEST_F(ProjectStorage, SynchronizeTypesOverwritesTypeAccessSemantics) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -829,31 +787,29 @@ TEST_F(ProjectStorage, SynchronizeTypesOverwritesTypeAccessSemantics) types[0].accessSemantics = TypeAccessSemantics::Value; types[1].accessSemantics = TypeAccessSemantics::Value; - storage.synchronize({}, imports, types, {sourceId1, sourceId2}, {}); + storage.synchronize(imports, types, {sourceId1, sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Value, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Value, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Value), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Value), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, + "QQuickItem")))))); } TEST_F(ProjectStorage, SynchronizeTypesOverwritesSources) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -861,132 +817,129 @@ TEST_F(ProjectStorage, SynchronizeTypesOverwritesSources) types[0].sourceId = sourceId3; types[1].sourceId = sourceId4; Storage::Imports newImports; - newImports.emplace_back("Qml", Storage::Version{}, sourceId3); - newImports.emplace_back("Qml", Storage::Version{}, sourceId4); - newImports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + newImports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3); + newImports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3); + newImports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + newImports.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId3); + newImports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4); + newImports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); - storage.synchronize({}, newImports, types, {sourceId1, sourceId2, sourceId3, sourceId4}, {}); + storage.synchronize(newImports, types, {sourceId1, sourceId2, sourceId3, sourceId4}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId4), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId3), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId4, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId3, + "QQuickItem", + fetchTypeId(sourceId4, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); } TEST_F(ProjectStorage, SynchronizeTypesInsertTypeIntoPrototypeChain) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[0].prototype = Storage::NativeType{"QQuickObject"}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{"QObject"}, + types[0].prototype = Storage::ImportedType{"QQuickObject"}; + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{"QObject"}, TypeAccessSemantics::Reference, sourceId1, - {Storage::ExportedType{"Object"}}}); + {Storage::ExportedType{qtQuickModuleId, "Object"}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickObject"}}}); - storage.synchronize({}, importsSourceId1, {types[0], types[2]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0], types[2]}, {sourceId1}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickObject", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QQuickObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickObject", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Object"), + IsExportedType(qtQuickNativeModuleId, "QQuickObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId1, "QQuickObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); } TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedPrototype) { Storage::Types types{createTypes()}; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"QtQuick", + Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{"QObject"}, + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{"QObject"}, TypeAccessSemantics::Reference, sourceId1, - {Storage::ExportedType{"Object"}}}); + {Storage::ExportedType{qtQuickModuleId, "Object"}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickObject"}}}); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickObject", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QQuickObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickObject", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Object"), + IsExportedType(qtQuickNativeModuleId, "QQuickObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId1, "QQuickObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); } TEST_F(ProjectStorage, SynchronizeTypesThrowsForMissingPrototype) { sourceId1 = sourcePathCache.sourceId(path1); - Storage::Types types{Storage::Type{qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, + Storage::Types types{Storage::Type{"QQuickItem", + Storage::ImportedType{"QObject"}, TypeAccessSemantics::Reference, sourceId1, - {Storage::ExportedType{"Item"}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item"}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}}}; ASSERT_THROW(storage.synchronize( - modules, imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -997,28 +950,25 @@ TEST_F(ProjectStorage, SynchronizeTypesThrowsForMissingPrototype) TEST_F(ProjectStorage, SynchronizeTypesThrowsForInvalidModule) { sourceId1 = sourcePathCache.sourceId(path1); - Storage::Types types{Storage::Type{ModuleId{}, - "QQuickItem", - Storage::NativeType{"QObject"}, + Storage::Types types{Storage::Type{"QQuickItem", + Storage::ImportedType{"QObject"}, TypeAccessSemantics::Reference, sourceId1, - {Storage::ExportedType{"Item"}}}}; + {Storage::ExportedType{ModuleId{}, "Item"}}}}; - ASSERT_THROW(storage.synchronize({}, imports, types, {sourceId1}, {}), + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1}, {}), QmlDesigner::ModuleDoesNotExists); } TEST_F(ProjectStorage, TypeWithInvalidSourceIdThrows) { - Storage::Types types{Storage::Type{qtQuickModuleId, - "QQuickItem", - Storage::NativeType{""}, + Storage::Types types{Storage::Type{"QQuickItem", + Storage::ImportedType{""}, TypeAccessSemantics::Reference, SourceId{}, - {Storage::ExportedType{"Item"}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item"}}}}; ASSERT_THROW(storage.synchronize( - modules, imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -1030,100 +980,92 @@ TEST_F(ProjectStorage, DeleteTypeIfSourceIdIsSynchronized) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types.erase(types.begin()); - storage.synchronize({}, importsSourceId2, types, {sourceId1, sourceId2}, {}); + storage.synchronize(importsSourceId2, types, {sourceId1, sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))))); + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))))); } TEST_F(ProjectStorage, DontDeleteTypeIfSourceIdIsNotSynchronized) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types.pop_back(); - storage.synchronize({}, importsSourceId1, types, {sourceId1}, {}); + storage.synchronize(importsSourceId1, types, {sourceId1}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); } TEST_F(ProjectStorage, UpdateExportedTypesIfTypeNameChanges) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].typeName = "QQuickItem2"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem2", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item")))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem2", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); } TEST_F(ProjectStorage, BreakingPrototypeChainByDeletingBaseComponentThrows) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types.pop_back(); - ASSERT_THROW(storage.synchronize({}, importsSourceId1, types, {sourceId1, sourceId2}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId1, types, {sourceId1, sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } @@ -1132,7 +1074,6 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarations) Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -1140,19 +1081,18 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarations) ASSERT_THAT(storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration( "children", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } @@ -1162,8 +1102,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationsWithMissingImports Storage::Types types{createTypes()}; types[0].propertyDeclarations.pop_back(); - ASSERT_THROW(storage.synchronize(modules, - {}, + ASSERT_THROW(storage.synchronize({}, types, {sourceId1, sourceId2, @@ -1178,14 +1117,13 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationsWithMissingImports { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Obj"}; - ASSERT_THROW(storage.synchronize({}, {}, {types[0]}, {sourceId1}, {}), + ASSERT_THROW(storage.synchronize({}, {types[0]}, {sourceId1}, {}), QmlDesigner::TypeNameDoesNotExists); } @@ -1193,16 +1131,14 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationQualifiedType) { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"QtQuick", Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{"QObject"}, + "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{"QObject"}, TypeAccessSemantics::Reference, sourceId1, - {Storage::ExportedType{"Object"}}}); + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -1210,19 +1146,18 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationQualifiedType) ASSERT_THAT(storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("data", - Storage::NativeType{"QQuickObject"}, + fetchTypeId(sourceId1, "QQuickObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration( "children", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } @@ -1231,29 +1166,27 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesPropertyDeclarationType) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[0].propertyDeclarations[0].typeName = Storage::NativeType{"QQuickItem"}; + types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QQuickItem"}; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("data", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration( "children", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } @@ -1262,30 +1195,28 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesDeclarationTraits) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsPointer), IsPropertyDeclaration( "children", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } @@ -1294,31 +1225,29 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesDeclarationTraitsAndType) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer; - types[0].propertyDeclarations[0].typeName = Storage::NativeType{"QQuickItem"}; + types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QQuickItem"}; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("data", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsPointer), IsPropertyDeclaration( "children", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } @@ -1327,25 +1256,23 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovesAPropertyDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].propertyDeclarations.pop_back(); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre(IsPropertyDeclaration( "data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } @@ -1353,36 +1280,34 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsAPropertyDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"object", - Storage::NativeType{"QObject"}, + Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsPointer}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT( storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("object", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsPointer), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("children", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } @@ -1391,30 +1316,28 @@ TEST_F(ProjectStorage, SynchronizeTypesRenameAPropertyDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].propertyDeclarations[1].name = "objects"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration( "objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } @@ -1422,11 +1345,10 @@ TEST_F(ProjectStorage, SynchronizeTypesRenameAPropertyDeclaration) TEST_F(ProjectStorage, UsingNonExistingNativePropertyTypeThrows) { Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::NativeType{"QObject2"}; + types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QObject2"}; types.pop_back(); - ASSERT_THROW(storage.synchronize(modules, - importsSourceId1, + ASSERT_THROW(storage.synchronize(importsSourceId1, types, {sourceId1, sourceId2, @@ -1443,8 +1365,7 @@ TEST_F(ProjectStorage, UsingNonExistingExportedPropertyTypeThrows) types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QObject2"}; types.pop_back(); - ASSERT_THROW(storage.synchronize(modules, - importsSourceId1, + ASSERT_THROW(storage.synchronize(importsSourceId1, types, {sourceId1, sourceId2, @@ -1459,11 +1380,10 @@ TEST_F(ProjectStorage, UsingNonExistingQualifiedExportedPropertyTypeWithWrongNam { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "QObject2", Storage::Import{"Qml", Storage::Version{}, sourceId1}}; + "QObject2", Storage::Import{qmlNativeModuleId, Storage::Version{}, sourceId1}}; types.pop_back(); - ASSERT_THROW(storage.synchronize(modules, - importsSourceId1, + ASSERT_THROW(storage.synchronize(importsSourceId1, types, {sourceId1, sourceId2, @@ -1478,11 +1398,10 @@ TEST_F(ProjectStorage, UsingNonExistingQualifiedExportedPropertyTypeWithWrongMod { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "QObject", Storage::Import{"QtQuick", Storage::Version{}, sourceId1}}; + "QObject", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; types.pop_back(); - ASSERT_THROW(storage.synchronize(modules, - importsSourceId1, + ASSERT_THROW(storage.synchronize(importsSourceId1, types, {sourceId1, sourceId2, @@ -1497,16 +1416,14 @@ TEST_F(ProjectStorage, BreakingPropertyDeclarationTypeDependencyByDeletingTypeTh { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[0].prototype = Storage::NativeType{}; + types[0].prototype = Storage::ImportedType{}; types.pop_back(); - ASSERT_THROW(storage.synchronize(modules, - importsSourceId1, + ASSERT_THROW(storage.synchronize(importsSourceId1, types, {sourceId1, sourceId2, @@ -1522,18 +1439,16 @@ TEST_F(ProjectStorage, SynchronizeTypesAddFunctionDeclarations) Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1])))))); @@ -1543,21 +1458,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationReturnType) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].functionDeclarations[1].returnTypeName = "item"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1])))))); @@ -1567,21 +1480,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationName) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].functionDeclarations[1].name = "name"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1])))))); @@ -1591,21 +1502,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationPopParameters) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].functionDeclarations[1].parameters.pop_back(); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1])))))); @@ -1615,21 +1524,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationAppendParameter { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].functionDeclarations[1].parameters.push_back(Storage::ParameterDeclaration{"arg4", "int"}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1])))))); @@ -1639,21 +1546,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationChangeParameter { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].functionDeclarations[1].parameters[0].name = "other"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1])))))); @@ -1663,21 +1568,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationChangeParameter { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].functionDeclarations[1].parameters[0].name = "long long"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1])))))); @@ -1687,21 +1590,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationChangeParameter { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].functionDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1])))))); @@ -1711,21 +1612,19 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovesFunctionDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].functionDeclarations.pop_back(); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0])))))); } @@ -1734,7 +1633,6 @@ TEST_F(ProjectStorage, SynchronizeTypesAddFunctionDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -1742,14 +1640,13 @@ TEST_F(ProjectStorage, SynchronizeTypesAddFunctionDeclaration) types[0].functionDeclarations.push_back( Storage::FunctionDeclaration{"name", "string", {Storage::ParameterDeclaration{"arg", "int"}}}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::functionDeclarations, UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), Eq(types[0].functionDeclarations[1]), @@ -1761,18 +1658,16 @@ TEST_F(ProjectStorage, SynchronizeTypesAddSignalDeclarations) Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), Eq(types[0].signalDeclarations[1])))))); @@ -1782,21 +1677,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationName) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].signalDeclarations[1].name = "name"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), Eq(types[0].signalDeclarations[1])))))); @@ -1806,21 +1699,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationPopParameters) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].signalDeclarations[1].parameters.pop_back(); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), Eq(types[0].signalDeclarations[1])))))); @@ -1830,21 +1721,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationAppendParameters) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].signalDeclarations[1].parameters.push_back(Storage::ParameterDeclaration{"arg4", "int"}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), Eq(types[0].signalDeclarations[1])))))); @@ -1854,21 +1743,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationChangeParameterNa { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].signalDeclarations[1].parameters[0].name = "other"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), Eq(types[0].signalDeclarations[1])))))); @@ -1878,21 +1765,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationChangeParameterTy { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].signalDeclarations[1].parameters[0].typeName = "long long"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), Eq(types[0].signalDeclarations[1])))))); @@ -1902,21 +1787,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationChangeParameterTr { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].signalDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), Eq(types[0].signalDeclarations[1])))))); @@ -1926,21 +1809,19 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovesSignalDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].signalDeclarations.pop_back(); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0])))))); } @@ -1949,7 +1830,6 @@ TEST_F(ProjectStorage, SynchronizeTypesAddSignalDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -1957,14 +1837,13 @@ TEST_F(ProjectStorage, SynchronizeTypesAddSignalDeclaration) types[0].signalDeclarations.push_back( Storage::SignalDeclaration{"name", {Storage::ParameterDeclaration{"arg", "int"}}}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::signalDeclarations, UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), Eq(types[0].signalDeclarations[1]), @@ -1976,18 +1855,16 @@ TEST_F(ProjectStorage, SynchronizeTypesAddEnumerationDeclarations) Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1])))))); @@ -1997,21 +1874,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationName) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].enumerationDeclarations[1].name = "Name"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1])))))); @@ -2021,21 +1896,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationPopEnumerato { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].enumerationDeclarations[1].enumeratorDeclarations.pop_back(); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1])))))); @@ -2045,7 +1918,6 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationAppendEnumer { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -2053,14 +1925,13 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationAppendEnumer types[0].enumerationDeclarations[1].enumeratorDeclarations.push_back( Storage::EnumeratorDeclaration{"Haa", 54}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1])))))); @@ -2070,21 +1941,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationChangeEnumer { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].enumerationDeclarations[1].enumeratorDeclarations[0].name = "Hoo"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1])))))); @@ -2094,21 +1963,19 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationChangeEnumer { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].enumerationDeclarations[1].enumeratorDeclarations[1].value = 11; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1])))))); @@ -2119,7 +1986,6 @@ TEST_F(ProjectStorage, { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -2127,14 +1993,13 @@ TEST_F(ProjectStorage, types[0].enumerationDeclarations[1].enumeratorDeclarations[0].value = 11; types[0].enumerationDeclarations[1].enumeratorDeclarations[0].hasValue = true; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1])))))); @@ -2145,21 +2010,19 @@ TEST_F(ProjectStorage, { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].enumerationDeclarations[1].enumeratorDeclarations[0].hasValue = false; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1])))))); @@ -2169,21 +2032,19 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovesEnumerationDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].enumerationDeclarations.pop_back(); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0])))))); } @@ -2192,7 +2053,6 @@ TEST_F(ProjectStorage, SynchronizeTypesAddEnumerationDeclaration) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -2200,203 +2060,29 @@ TEST_F(ProjectStorage, SynchronizeTypesAddEnumerationDeclaration) types[0].enumerationDeclarations.push_back( Storage::EnumerationDeclaration{"name", {Storage::EnumeratorDeclaration{"Foo", 98, true}}}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), Eq(types[0].enumerationDeclarations[1]), Eq(types[0].enumerationDeclarations[2])))))); } -TEST_F(ProjectStorage, SynchronizeModulesAddModules) -{ - Storage::Modules modules{createModules()}; - - storage.synchronize(modules, {}, {}, {qmlModuleSourceId, qtQuickModuleSourceId, moduleSourceId5}, {}); - - ASSERT_THAT(storage.fetchAllModules(), - UnorderedElementsAre(IsModule("Qml", qmlModuleSourceId), - IsModule("QtQuick", qtQuickModuleSourceId), - IsModule("/path/to", pathToModuleSourceId))); -} - -TEST_F(ProjectStorage, SynchronizeModulesAddModulesAgain) -{ - Storage::Modules modules{createModules()}; - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - - ASSERT_THAT(storage.fetchAllModules(), - UnorderedElementsAre(IsModule("Qml", qmlModuleSourceId), - IsModule("QtQuick", qtQuickModuleSourceId), - IsModule("/path/to", pathToModuleSourceId))); -} - -TEST_F(ProjectStorage, SynchronizeModulesUpdateToMoreModules) -{ - Storage::Modules modules{createModules()}; - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - modules.push_back(Storage::Module{"QtQuick.Foo", moduleSourceId4}); - - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId, moduleSourceId4}, - {}); - - ASSERT_THAT(storage.fetchAllModules(), - UnorderedElementsAre(IsModule("Qml", qmlModuleSourceId), - IsModule("QtQuick", qtQuickModuleSourceId), - IsModule("/path/to", pathToModuleSourceId), - IsModule("QtQuick.Foo", moduleSourceId4))); -} - -TEST_F(ProjectStorage, SynchronizeModulesAddOneMoreModules) -{ - Storage::Modules modules{createModules()}; - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - auto newModule = Storage::Module{"QtQuick.Foo", moduleSourceId4}; - - storage.synchronize({newModule}, {}, {}, {moduleSourceId4}, {}); - - ASSERT_THAT(storage.fetchAllModules(), - UnorderedElementsAre(IsModule("Qml", qmlModuleSourceId), - IsModule("QtQuick", qtQuickModuleSourceId), - IsModule("/path/to", pathToModuleSourceId), - IsModule("QtQuick.Foo", moduleSourceId4))); -} - -TEST_F(ProjectStorage, SynchronizeModulesRemoveModule) -{ - Storage::Modules modules{createModules()}; - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - - storage.synchronize({}, {}, {}, {pathToModuleSourceId}, {}); - - ASSERT_THAT(storage.fetchAllModules(), - UnorderedElementsAre(IsModule("Qml", qmlModuleSourceId), - IsModule("QtQuick", qtQuickModuleSourceId))); -} - -TEST_F(ProjectStorage, SynchronizeModulesChangeSourceId) -{ - Storage::Modules modules{createModules()}; - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - modules[1].sourceId = moduleSourceId4; - - storage.synchronize({modules[1]}, {}, {}, {qtQuickModuleSourceId, moduleSourceId4}, {}); - - ASSERT_THAT(storage.fetchAllModules(), - UnorderedElementsAre(IsModule("Qml", qmlModuleSourceId), - IsModule("QtQuick", moduleSourceId4), - IsModule("/path/to", pathToModuleSourceId))); -} - -TEST_F(ProjectStorage, SynchronizeModulesChangeName) -{ - Storage::Modules modules{createModules()}; - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - modules[0].name = "Qml2"; - - storage.synchronize(modules, - {}, - {}, - {qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - - ASSERT_THAT(storage.fetchAllModules(), - UnorderedElementsAre(IsModule("Qml2", qmlModuleSourceId), - IsModule("QtQuick", qtQuickModuleSourceId), - IsModule("/path/to", pathToModuleSourceId))); -} - -TEST_F(ProjectStorage, RemovingModuleRemovesDependentTypesToo) +TEST_F(ProjectStorage, FetchTypeIdBySourceIdAndName) { Storage::Types types{createTypes()}; - types[0].prototype = Storage::NativeType{""}; - types[0].propertyDeclarations.clear(); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - storage.synchronize({}, {}, {}, {qtQuickModuleSourceId, pathToModuleSourceId}, {}); - - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2))); -} - -TEST_F(ProjectStorage, RemovingModuleThrowsForMissingType) -{ - Storage::Types types{createTypes()}; - imports.emplace_back("QtQuick", Storage::Version{}, sourceId2); - types[0].prototype = Storage::NativeType{""}; - types[0].propertyDeclarations.clear(); - types[1].prototype = Storage::ImportedType{"Item"}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - - ASSERT_THROW(storage.synchronize({}, {}, {}, {qtQuickModuleSourceId, pathToModuleSourceId}, {}), - QmlDesigner::TypeNameDoesNotExists); -} - -TEST_F(ProjectStorage, FetchTypeIdByModuleIdAndName) -{ - Storage::Types types{createTypes()}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - auto qmlModuleId = storage.fetchModuleId("Qml"); - - auto typeId = storage.fetchTypeIdByName(qmlModuleId, "QObject"); + auto typeId = storage.fetchTypeIdByName(sourceId2, "QObject"); ASSERT_THAT(storage.fetchTypeIdByExportedName("Object"), Eq(typeId)); } @@ -2405,45 +2091,40 @@ TEST_F(ProjectStorage, FetchTypeIdByExportedName) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - auto qmlModuleId = storage.fetchModuleId("Qml"); auto typeId = storage.fetchTypeIdByExportedName("Object"); - ASSERT_THAT(storage.fetchTypeIdByName(qmlModuleId, "QObject"), Eq(typeId)); + ASSERT_THAT(storage.fetchTypeIdByName(sourceId2, "QObject"), Eq(typeId)); } TEST_F(ProjectStorage, FetchTypeIdByImporIdsAndExportedName) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - auto qmlModuleId = storage.fetchModuleId("Qml"); - auto qtQuickModuleId = storage.fetchModuleId("QtQuick"); auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({qmlModuleId, qtQuickModuleId}, "Object"); - ASSERT_THAT(storage.fetchTypeIdByName(qmlModuleId, "QObject"), Eq(typeId)); + ASSERT_THAT(storage.fetchTypeIdByName(sourceId2, "QObject"), Eq(typeId)); } TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAreEmpty) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); + auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({}, "Object"); ASSERT_FALSE(typeId.isValid()); @@ -2453,11 +2134,11 @@ TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAre { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); + auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({ModuleId{}}, "Object"); ASSERT_FALSE(typeId.isValid()); @@ -2467,12 +2148,12 @@ TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfNotInModule) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - auto qtQuickModuleId = storage.fetchModuleId("QtQuick"); + auto qtQuickModuleId = storage.moduleId("QtQuick"); + auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({qtQuickModuleId}, "Object"); ASSERT_FALSE(typeId.isValid()); @@ -2482,8 +2163,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarations) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2496,30 +2176,28 @@ TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarations) ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsAgain) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2530,8 +2208,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsAgain) pathToModuleSourceId}, {}); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2544,30 +2221,28 @@ TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsAgain) ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, SynchronizeTypesRemoveAliasDeclarations) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2579,32 +2254,31 @@ TEST_F(ProjectStorage, SynchronizeTypesRemoveAliasDeclarations) {}); types[2].propertyDeclarations.pop_back(); - storage.synchronize({}, importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsThrowsForWrongTypeName) { Storage::Types types{createTypesWithAliases()}; - types[2].propertyDeclarations[1].typeName = Storage::NativeType{"QQuickItemWrong"}; + types[2].propertyDeclarations[1].typeName = Storage::ImportedType{"QQuickItemWrong"}; - ASSERT_THROW(storage.synchronize(modules, importsSourceId4, {types[2]}, {sourceId4}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId4, {types[2]}, {sourceId4}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsThrowsForWrongPropertyName) @@ -2612,15 +2286,14 @@ TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsThrowsForWrongPropert Storage::Types types{createTypesWithAliases()}; types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; - ASSERT_THROW(storage.synchronize(modules, imports, types, {sourceId4}, {}), + ASSERT_THROW(storage.synchronize(imports, types, {sourceId4}, {}), QmlDesigner::PropertyNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsTypeName) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2631,36 +2304,34 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsTypeName) pathToModuleSourceId}, {}); types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Obj2"}; - importsSourceId3.emplace_back("/path/to", Storage::Version{}, sourceId3); + importsSourceId3.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); - storage.synchronize({}, importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsPropertyName) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2672,36 +2343,34 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsPropertyName) {}); types[2].propertyDeclarations[2].aliasPropertyName = "children"; - storage.synchronize({}, importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); ASSERT_THAT( storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsToPropertyDeclaration) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2714,32 +2383,31 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsToPropertyDeclarat types[2].propertyDeclarations.pop_back(); types[2].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QQuickItem"}, + Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize({}, importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); ASSERT_THAT( storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } @@ -2750,11 +2418,10 @@ TEST_F(ProjectStorage, SynchronizeTypesChangePropertyDeclarationsToAliasDeclarat typesChanged[2].propertyDeclarations.pop_back(); typesChanged[2].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QQuickItem"}, + Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(modules, - imports, + storage.synchronize(imports, typesChanged, {sourceId1, sourceId2, @@ -2765,34 +2432,32 @@ TEST_F(ProjectStorage, SynchronizeTypesChangePropertyDeclarationsToAliasDeclarat pathToModuleSourceId}, {}); - storage.synchronize({}, imports, types, {sourceId1, sourceId2, sourceId3, sourceId4}, {}); + storage.synchronize(imports, types, {sourceId1, sourceId2, sourceId3, sourceId4}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTraits) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2805,36 +2470,34 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTrait types[1].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly; - storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); ASSERT_THAT( storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTypeName) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2845,36 +2508,34 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTypeN pathToModuleSourceId}, {}); types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Item"}; - importsSourceId2.emplace_back("QtQuick", Storage::Version{}, sourceId2); + importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationWithAnAliasThrows) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2886,15 +2547,14 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationWithAnAliasThrow {}); types[1].propertyDeclarations.pop_back(); - ASSERT_THROW(storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), Sqlite::ConstraintPreventsModification); } TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationAndAlias) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2907,27 +2567,25 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationAndAlias) types[1].propertyDeclarations.pop_back(); types[2].propertyDeclarations.pop_back(); - storage.synchronize({}, - importsSourceId2 + importsSourceId3, + storage.synchronize(importsSourceId2 + importsSourceId3, {types[1], types[2]}, {sourceId2, sourceId3}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } @@ -2935,9 +2593,8 @@ TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeWithAliasTargetPropertyDeclarat { Storage::Types types{createTypesWithAliases()}; types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId3); - storage.synchronize(modules, - imports, + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2948,16 +2605,15 @@ TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeWithAliasTargetPropertyDeclarat pathToModuleSourceId}, {}); - ASSERT_THROW(storage.synchronize({}, {}, {}, {sourceId4}, {}), QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize({}, {}, {sourceId4}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeAndAliasPropertyDeclaration) { Storage::Types types{createTypesWithAliases()}; types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId3); - storage.synchronize(modules, - imports, + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -2969,35 +2625,32 @@ TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeAndAliasPropertyDeclaration) {}); types[2].propertyDeclarations.pop_back(); - storage.synchronize({}, - importsSourceId1 + importsSourceId3, + storage.synchronize(importsSourceId1 + importsSourceId3, {types[0], types[2]}, {sourceId1, sourceId3}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, UpdateAliasPropertyIfPropertyIsOverloaded) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3009,32 +2662,31 @@ TEST_F(ProjectStorage, UpdateAliasPropertyIfPropertyIsOverloaded) {}); types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QQuickItem"}, + Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT( storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } @@ -3043,12 +2695,11 @@ TEST_F(ProjectStorage, AliasPropertyIsOverloaded) Storage::Types types{createTypesWithAliases()}; types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QQuickItem"}, + Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3062,23 +2713,22 @@ TEST_F(ProjectStorage, AliasPropertyIsOverloaded) ASSERT_THAT( storage.fetchTypes(), Contains( - AllOf(IsStorageType(qtQuickModuleId, + AllOf(IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } @@ -3087,11 +2737,10 @@ TEST_F(ProjectStorage, UpdateAliasPropertyIfOverloadedPropertyIsRemoved) Storage::Types types{createTypesWithAliases()}; types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QQuickItem"}, + Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3103,37 +2752,35 @@ TEST_F(ProjectStorage, UpdateAliasPropertyIfOverloadedPropertyIsRemoved) {}); types[0].propertyDeclarations.pop_back(); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, RelinkAliasProperty) { Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::NativeType{"QObject2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId2); - storage.synchronize(modules, - imports, + types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3143,28 +2790,27 @@ TEST_F(ProjectStorage, RelinkAliasProperty) qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[3].moduleId = qtQuickModuleId; + types[3].exportedTypes[0].moduleId = qtQuickModuleId; - storage.synchronize({}, importsSourceId4, {types[3]}, {sourceId4}, {}); + storage.synchronize(importsSourceId4, {types[3]}, {sourceId4}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject2"}, + fetchTypeId(sourceId4, "QObject2"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } @@ -3172,10 +2818,9 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForQualifiedImportedTypeName) { Storage::Types types{createTypesWithAliases()}; types[1].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object2", Storage::Import{"/path/to", Storage::Version{}, sourceId2}}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - storage.synchronize(modules, - imports, + "Object2", Storage::Import{pathToModuleId, Storage::Version{}, sourceId2}}; + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3185,10 +2830,10 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForQualifiedImportedTypeName) qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[3].moduleId = qtQuickModuleId; - importsSourceId4.emplace_back("QtQuick", Storage::Version{}, sourceId4); + types[3].exportedTypes[0].moduleId = qtQuickModuleId; + importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4); - ASSERT_THROW(storage.synchronize({}, importsSourceId4, {types[3]}, {sourceId4}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId4, {types[3]}, {sourceId4}, {}), QmlDesigner::TypeNameDoesNotExists); } @@ -3197,17 +2842,16 @@ TEST_F(ProjectStorage, { Storage::Types types{createTypesWithAliases()}; types[1].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object2", Storage::Import{"/path/to", Storage::Version{}, sourceId2}}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - types.push_back(Storage::Type{qtQuickModuleId, - "QObject2", - Storage::NativeType{}, + "Object2", Storage::Import{pathToModuleId, Storage::Version{}, sourceId2}}; + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + types.push_back(Storage::Type{"QObject2", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId5, - {Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}}); + {Storage::ExportedType{qtQuickModuleId, "Object2"}, + Storage::ExportedType{qtQuickModuleId, "Obj2"}}}); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3221,22 +2865,21 @@ TEST_F(ProjectStorage, ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject2"}, + fetchTypeId(sourceId4, "QObject2"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } @@ -3245,8 +2888,7 @@ TEST_F(ProjectStorage, RelinkAliasPropertyReactToTypeNameChange) Storage::Types types{createTypesWithAliases2()}; types[2].propertyDeclarations.push_back( Storage::PropertyDeclaration{"items", Storage::ImportedType{"Item"}, "children"}); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3258,38 +2900,35 @@ TEST_F(ProjectStorage, RelinkAliasPropertyReactToTypeNameChange) {}); types[0].typeName = "QQuickItem2"; - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( - IsStorageType(qtQuickModuleId, + IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, UnorderedElementsAre( IsPropertyDeclaration("items", - Storage::NativeType{"QQuickItem2"}, + fetchTypeId(sourceId1, "QQuickItem2"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly), IsPropertyDeclaration("objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList), IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedType) { Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::NativeType{"QObject2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId2); - - storage.synchronize(modules, - imports, + types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3299,25 +2938,24 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedType) qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[3].moduleId = qtQuickModuleId; + types[3].exportedTypes[0].moduleId = qtQuickModuleId; - storage.synchronize({}, importsSourceId4, {types[3]}, {sourceId3, sourceId4}, {}); + storage.synchronize(importsSourceId4, {types[3]}, {sourceId3, sourceId4}, {}); ASSERT_THAT(storage.fetchTypes(), - Not(Contains(AllOf(IsStorageType(qtQuickModuleId, - "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3))))); + Not(Contains(IsStorageType(sourceId3, + "QAliasItem", + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference)))); } TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyType) { Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::NativeType{"QObject2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - storage.synchronize(modules, - imports, + types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3327,14 +2965,13 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyType) qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[0].prototype = Storage::NativeType{}; - importsSourceId1.emplace_back("/path/to", Storage::Version{}, sourceId1); - importsSourceId4.emplace_back("QtQuick", Storage::Version{}, sourceId4); + types[0].prototype = Storage::ImportedType{}; + importsSourceId1.emplace_back(pathToModuleId, Storage::Version{}, sourceId1); + importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4); types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; types[3].propertyDeclarations[0].typeName = Storage::ImportedType{"Item"}; - storage.synchronize({}, - importsSourceId1 + importsSourceId4, + storage.synchronize(importsSourceId1 + importsSourceId4, {types[0], types[3]}, {sourceId1, sourceId2, sourceId3, sourceId4}, {}); @@ -3345,10 +2982,9 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyType) TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyTypeNameChange) { Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::NativeType{"QObject2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - storage.synchronize(modules, - imports, + types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3358,32 +2994,29 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyTypeName qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[3].moduleId = qtQuickModuleId; - types[1].propertyDeclarations[0].typeName = Storage::NativeType{"QObject"}; - importsSourceId4.emplace_back("QtQuick", Storage::Version{}, sourceId4); + types[3].exportedTypes[0].moduleId = qtQuickModuleId; + types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"QObject"}; + importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4); - storage.synchronize({}, - importsSourceId2 + importsSourceId4, + storage.synchronize(importsSourceId2 + importsSourceId4, {types[1], types[3]}, {sourceId2, sourceId3, sourceId4}, {}); ASSERT_THAT(storage.fetchTypes(), - Not(Contains(IsStorageType(qtQuickModuleId, + Not(Contains(IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3)))); + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference)))); } TEST_F(ProjectStorage, DoNotRelinkPropertyTypeDoesNotExists) { Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::NativeType{"QObject2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId2); - storage.synchronize(modules, - imports, + types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3393,18 +3026,16 @@ TEST_F(ProjectStorage, DoNotRelinkPropertyTypeDoesNotExists) qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types.pop_back(); - ASSERT_THROW(storage.synchronize({}, {}, {}, {sourceId4}, {}), QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize({}, {}, {sourceId4}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, DoNotRelinkAliasPropertyTypeDoesNotExists) { Storage::Types types{createTypesWithAliases2()}; - types[1].propertyDeclarations[0].typeName = Storage::NativeType{"QObject2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - storage.synchronize(modules, - imports, + types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3415,67 +3046,62 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyTypeDoesNotExists) pathToModuleSourceId}, {}); - ASSERT_THROW(storage.synchronize({}, {}, {}, {sourceId1}, {}), QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize({}, {}, {sourceId1}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, ChangePrototypeTypeName) { Storage::Types types{createTypesWithExportedTypeNamesOnly()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[1].typeName = "QObject3"; - storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject3"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId2, "QObject3"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, ChangePrototypeTypeModuleId) { Storage::Types types{createTypes()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[1].moduleId = qtQuickModuleId; + types[1].exportedTypes[2].moduleId = qtQuickModuleId; - storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference))); } -TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleIdThows) +TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleIdThrows) { Storage::Types types{createTypes()}; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"Qml", + Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[1].moduleId = qtQuickModuleId; + types[1].exportedTypes[0].moduleId = qtQuickModuleId; - ASSERT_THROW(storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } @@ -3483,55 +3109,53 @@ TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleId) { Storage::Types types{createTypes()}; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"Qml", + Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[1].moduleId = qtQuickModuleId; + types[1].exportedTypes[0].moduleId = qtQuickModuleId; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"QtQuick", + Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - storage.synchronize({}, - importsSourceId1 + importsSourceId2, + storage.synchronize(importsSourceId1 + importsSourceId2, {types[0], types[1]}, {sourceId1, sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, ChangePrototypeTypeNameAndModuleId) { Storage::Types types{createTypesWithExportedTypeNamesOnly()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[1].moduleId = qtQuickModuleId; + types[1].exportedTypes[0].moduleId = qtQuickModuleId; + types[1].exportedTypes[1].moduleId = qtQuickModuleId; + types[1].exportedTypes[2].moduleId = qtQuickModuleId; + types[1].exportedTypes[2].name = "QObject3"; types[1].typeName = "QObject3"; - storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject3"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId2, "QObject3"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, ChangePrototypeTypeNameThrowsForWrongNativePrototupeTypeName) @@ -3539,14 +3163,14 @@ TEST_F(ProjectStorage, ChangePrototypeTypeNameThrowsForWrongNativePrototupeTypeN Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object"}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); + types[1].exportedTypes[2].name = "QObject3"; types[1].typeName = "QObject3"; - ASSERT_THROW(storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } @@ -3554,18 +3178,17 @@ TEST_F(ProjectStorage, ThrowForPrototypeChainCycles) { Storage::Types types{createTypes()}; types[1].prototype = Storage::ImportedType{"Object2"}; - types.push_back(Storage::Type{pathToModuleId, - "QObject2", + types.push_back(Storage::Type{"QObject2", Storage::ImportedType{"Item"}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}}); - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); - imports.emplace_back("/path/to", Storage::Version{}, sourceId3); + {Storage::ExportedType{pathToModuleId, "Object2"}, + Storage::ExportedType{pathToModuleId, "Obj2"}}}); + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); - ASSERT_THROW(storage.synchronize(modules, - imports, + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3582,8 +3205,7 @@ TEST_F(ProjectStorage, ThrowForTypeIdAndPrototypeIdAreTheSame) Storage::Types types{createTypes()}; types[1].prototype = Storage::ImportedType{"Object"}; - ASSERT_THROW(storage.synchronize(modules, - imports, + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3598,16 +3220,15 @@ TEST_F(ProjectStorage, ThrowForTypeIdAndPrototypeIdAreTheSameForRelinking) { Storage::Types types{createTypesWithExportedTypeNamesOnly()}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[1].prototype = Storage::ImportedType{"Item"}; types[1].typeName = "QObject2"; - importsSourceId2.emplace_back("QtQuick", Storage::Version{}, sourceId2); + importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - ASSERT_THROW(storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), QmlDesigner::PrototypeChainCycle); } @@ -3615,8 +3236,7 @@ TEST_F(ProjectStorage, RecursiveAliases) { Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3629,23 +3249,21 @@ TEST_F(ProjectStorage, RecursiveAliases) {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId5, "QAliasItem2", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId5), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, ElementsAre(IsPropertyDeclaration( "objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, RecursiveAliasesChangePropertyType) { Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3657,28 +3275,26 @@ TEST_F(ProjectStorage, RecursiveAliasesChangePropertyType) pathToModuleSourceId}, {}); types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - importsSourceId2.emplace_back("/path/to", Storage::Version{}, sourceId2); + importsSourceId2.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId5, "QAliasItem2", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId5), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, ElementsAre(IsPropertyDeclaration( "objects", - Storage::NativeType{"QObject2"}, + fetchTypeId(sourceId4, "QObject2"), Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorage, UpdateAliasesAfterInjectingProperty) { Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3695,18 +3311,17 @@ TEST_F(ProjectStorage, UpdateAliasesAfterInjectingProperty) Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId5, "QAliasItem2", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId5), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, ElementsAre(IsPropertyDeclaration( "objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } @@ -3714,8 +3329,7 @@ TEST_F(ProjectStorage, UpdateAliasesAfterInjectingProperty) TEST_F(ProjectStorage, UpdateAliasesAfterChangeAliasToProperty) { Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3733,30 +3347,28 @@ TEST_F(ProjectStorage, UpdateAliasesAfterChangeAliasToProperty) Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize({}, importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); ASSERT_THAT(storage.fetchTypes(), - AllOf(Contains(AllOf(IsStorageType(qtQuickModuleId, + AllOf(Contains(AllOf(IsStorageType(sourceId5, "QAliasItem2", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId5), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, ElementsAre(IsPropertyDeclaration( "objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly, "objects"))))), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId3, "QAliasItem", - Storage::NativeType{"QQuickItem"}, - TypeAccessSemantics::Reference, - sourceId3), + fetchTypeId(sourceId1, "QQuickItem"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, ElementsAre(IsPropertyDeclaration( "objects", - Storage::NativeType{"QQuickItem"}, + fetchTypeId(sourceId1, "QQuickItem"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly, ""))))))); @@ -3767,8 +3379,7 @@ TEST_F(ProjectStorage, UpdateAliasesAfterChangePropertyToAlias) Storage::Types types{createTypesWithRecursiveAliases()}; types[3].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3782,20 +3393,19 @@ TEST_F(ProjectStorage, UpdateAliasesAfterChangePropertyToAlias) types[1].propertyDeclarations.clear(); types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"Object2"}, "objects"}); - importsSourceId2.emplace_back("/path/to", Storage::Version{}, sourceId2); + importsSourceId2.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId5, "QAliasItem2", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId5), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, ElementsAre(IsPropertyDeclaration( "objects", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly, "objects")))))); @@ -3807,10 +3417,9 @@ TEST_F(ProjectStorage, CheckForProtoTypeCycleThrows) types[1].propertyDeclarations.clear(); types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"AliasItem2"}, "objects"}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId2); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - ASSERT_THROW(storage.synchronize(modules, - imports, + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3827,8 +3436,7 @@ TEST_F(ProjectStorage, CheckForProtoTypeCycleThrows) TEST_F(ProjectStorage, CheckForProtoTypeCycleAfterUpdateThrows) { Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3842,9 +3450,9 @@ TEST_F(ProjectStorage, CheckForProtoTypeCycleAfterUpdateThrows) types[1].propertyDeclarations.clear(); types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"AliasItem2"}, "objects"}); - importsSourceId2.emplace_back("QtQuick", Storage::Version{}, sourceId2); + importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - ASSERT_THROW(storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), QmlDesigner::AliasChainCycle); } @@ -3852,42 +3460,38 @@ TEST_F(ProjectStorage, QualifiedPrototype) { Storage::Types types{createTypes()}; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"Qml", + Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, QualifiedPrototypeUpperDownTheModuleChainThrows) { Storage::Types types{createTypes()}; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"QtQuick", + Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - ASSERT_THROW(storage.synchronize(modules, - imports, + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3902,49 +3506,44 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain) { Storage::Types types{createTypes()}; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"QtQuick", + Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QQuickObject"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId3, "QQuickObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, QualifiedPrototypeWithWrongVersionThrows) { Storage::Types types{createTypes()}; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"Qml", + Storage::Import{qmlModuleId, Storage::Version{4}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); - ASSERT_THROW(storage.synchronize(modules, - imports, + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -3961,27 +3560,24 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersion) Storage::Types types{createTypes()}; imports[0].version = Storage::Version{2}; types[0].prototype = Storage::QualifiedImportedType{"Object", imports[0]}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain) @@ -3990,39 +3586,36 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain) imports[2].version = Storage::Version{2}; types[0].prototype = Storage::QualifiedImportedType{"Object", imports[2]}; types[0].exportedTypes[0].version = Storage::Version{2}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object", Storage::Version{2}}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + types.push_back( + Storage::Type{"QQuickObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{qtQuickModuleId, "Object", Storage::Version{2}}}}); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QQuickObject"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId3, "QQuickObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, QualifiedPrototypeWithVersionDownTheProtoTypeChainThrows) { Storage::Types types{createTypes()}; types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"QtQuick", + Storage::Import{qtQuickModuleId, Storage::Version{2}, sourceId1}}; - ASSERT_THROW(storage.synchronize(modules, - imports, + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -4038,17 +3631,15 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName) { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"Qml", Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, + "Object", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -4058,7 +3649,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName) Contains( Field(&Storage::Type::propertyDeclarations, Contains(IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList))))); } @@ -4066,10 +3657,9 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameDownTheModuleChainThr { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"QtQuick", Storage::Version{}, sourceId1}}; + "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - ASSERT_THROW(storage.synchronize(modules, - imports, + ASSERT_THROW(storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -4085,17 +3675,15 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameInTheModuleChain) { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"QtQuick", Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, + "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; + types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -4105,7 +3693,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameInTheModuleChain) Contains( Field(&Storage::Type::propertyDeclarations, Contains(IsPropertyDeclaration("data", - Storage::NativeType{"QQuickObject"}, + fetchTypeId(sourceId3, "QQuickObject"), Storage::PropertyDeclarationTraits::IsList))))); } @@ -4113,11 +3701,10 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameWithVersion) { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"Qml", Storage::Version{2}, sourceId1}}; - imports.emplace_back("Qml", Storage::Version{2}, sourceId1); + "Object", Storage::Import{qmlModuleId, Storage::Version{2}, sourceId1}}; + imports.emplace_back(qmlModuleId, Storage::Version{2}, sourceId1); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, @@ -4127,7 +3714,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameWithVersion) Contains( Field(&Storage::Type::propertyDeclarations, Contains(IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList))))); } @@ -4135,16 +3722,15 @@ TEST_F(ProjectStorage, ChangePropertyTypeModuleIdWithQualifiedTypeThrows) { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"Qml", Storage::Version{}, sourceId1}}; + "Object", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - types[1].moduleId = qtQuickModuleId; + types[1].exportedTypes[0].moduleId = qtQuickModuleId; - ASSERT_THROW(storage.synchronize({}, importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } @@ -4152,30 +3738,28 @@ TEST_F(ProjectStorage, ChangePropertyTypeModuleIdWithQualifiedType) { Storage::Types types{createTypes()}; types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"Qml", Storage::Version{}, sourceId1}}; + "Object", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"QtQuick", Storage::Version{}, sourceId1}}; - types[1].moduleId = qtQuickModuleId; - imports.emplace_back("QtQuick", Storage::Version{}, sourceId2); + "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; + types[1].exportedTypes[0].moduleId = qtQuickModuleId; + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - storage.synchronize({}, imports, types, {sourceId1, sourceId2}, {}); + storage.synchronize(imports, types, {sourceId1, sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, + Contains(AllOf(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::propertyDeclarations, Contains(IsPropertyDeclaration( "data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList)))))); } @@ -4184,7 +3768,7 @@ TEST_F(ProjectStorage, AddFileStatuses) FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); ASSERT_THAT(convert(storage.fetchAllFileStatuses()), UnorderedElementsAre(fileStatus1, fileStatus2)); @@ -4194,9 +3778,9 @@ TEST_F(ProjectStorage, RemoveFileStatus) { FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); - storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {fileStatus1}); + storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1}); ASSERT_THAT(convert(storage.fetchAllFileStatuses()), UnorderedElementsAre(fileStatus1)); } @@ -4206,9 +3790,9 @@ TEST_F(ProjectStorage, UpdateFileStatus) FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; FileStatus fileStatus2b{sourceId2, 102, 102}; - storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); - storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2b}); + storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2b}); ASSERT_THAT(convert(storage.fetchAllFileStatuses()), UnorderedElementsAre(fileStatus1, fileStatus2b)); @@ -4218,7 +3802,7 @@ TEST_F(ProjectStorage, ThrowForInvalidSourceId) { FileStatus fileStatus1{SourceId{}, 100, 100}; - ASSERT_THROW(storage.synchronize({}, {}, {}, {sourceId1}, {fileStatus1}), + ASSERT_THROW(storage.synchronize({}, {}, {sourceId1}, {fileStatus1}), Sqlite::ConstraintPreventsModification); } @@ -4226,7 +3810,7 @@ TEST_F(ProjectStorage, FetchAllFileStatuses) { FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); auto fileStatuses = convert(storage.fetchAllFileStatuses()); @@ -4237,7 +3821,7 @@ TEST_F(ProjectStorage, FetchAllFileStatusesReverse) { FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {fileStatus2, fileStatus1}); + storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus2, fileStatus1}); auto fileStatuses = convert(storage.fetchAllFileStatuses()); @@ -4248,7 +3832,7 @@ TEST_F(ProjectStorage, FetchFileStatus) { FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); auto fileStatus = storage.fetchFileStatus(sourceId1); @@ -4258,8 +3842,7 @@ TEST_F(ProjectStorage, FetchFileStatus) TEST_F(ProjectStorage, SynchronizeTypesWithoutTypeName) { Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, sourceId2, @@ -4270,17 +3853,15 @@ TEST_F(ProjectStorage, SynchronizeTypesWithoutTypeName) pathToModuleSourceId}, {}); types[3].typeName.clear(); - types[3].moduleId = ModuleId{}; types[3].prototype = Storage::ImportedType{"Object"}; - storage.synchronize({}, importsSourceId4, {types[3]}, {sourceId4}, {}); + storage.synchronize(importsSourceId4, {types[3]}, {sourceId4}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(pathToModuleId, + Contains(AllOf(IsStorageType(sourceId4, "QObject2", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId4), + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), Field(&Storage::Type::exportedTypes, UnorderedElementsAre(IsExportedType("Object2"), IsExportedType("Obj2")))))); @@ -4289,125 +3870,111 @@ TEST_F(ProjectStorage, SynchronizeTypesWithoutTypeName) TEST_F(ProjectStorage, FetchByMajorVersionForImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Object"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{1}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{1}, sourceId2}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchByMajorVersionForQualifiedImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{1}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{1}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Object", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{1, 2}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{1, 2}, sourceId2}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{1, 2}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{1, 2}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForImportedTypeIfMinorVersionIsNotExportedThrows) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Object"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{1, 1}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2}; - ASSERT_THROW(storage.synchronize({}, {import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } @@ -4415,436 +3982,439 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedTypeIfMinorVersionIsNotExportedThrows) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{1, 1}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Object", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - ASSERT_THROW(storage.synchronize({}, {import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchLowMinorVersionForImportedTypeThrows) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{1, 1}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2}; - ASSERT_THROW(storage.synchronize({}, {import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchLowMinorVersionForQualifiedImportedTypeThrows) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{1, 1}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - ASSERT_THROW(storage.synchronize({}, {import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchHigherMinorVersionForImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{1, 3}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{1, 3}, sourceId2}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchHigherMinorVersionForQualifiedImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{1, 3}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{1, 3}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchDifferentMajorVersionForImportedTypeThrows) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{3, 1}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{3, 1}, sourceId2}; - ASSERT_THROW(storage.synchronize({}, {import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchDifferentMajorVersionForQualifiedImportedTypeThrows) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{3, 1}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{3, 1}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - ASSERT_THROW(storage.synchronize({}, {import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{2, 3}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{2, 3}, sourceId2}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject2"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject2"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForQualifiedImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{2, 3}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{2, 3}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject2"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject2"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{}, sourceId2}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject4"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject4"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForQualifiedImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject4"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject4"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{2}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{2}, sourceId2}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject3"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject3"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForQualifiedImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{2}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{2}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject3"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject3"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Type type{"Item", Storage::ImportedType{"BuiltInObj"}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; - Storage::Import import{"Qml", Storage::Version{}, sourceId2}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; + Storage::Import import{qmlModuleId, Storage::Version{}, sourceId2}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForQualifiedImportedType) { auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, + storage.synchronize(imports, types, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Import import{"Qml", Storage::Version{}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + Storage::Import import{qmlModuleId, Storage::Version{}, sourceId2}; + Storage::Type type{"Item", Storage::QualifiedImportedType{"BuiltInObj", import}, TypeAccessSemantics::Reference, sourceId2, - {Storage::ExportedType{"Item", Storage::Version{}}}}; + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({}, {import}, {type}, {sourceId2}, {}); + storage.synchronize({import}, {type}, {sourceId2}, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(IsStorageType(qtQuickModuleId, + Contains(IsStorageType(sourceId2, "Item", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId2))); + fetchTypeId(sourceId1, "QObject"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, EnsureThatPropertiesForRemovedTypesAreNotAnymoreRelinked) { - Storage::Type type{qmlModuleId, - "QObject", - Storage::NativeType{""}, + Storage::Type type{"QObject", + Storage::ImportedType{""}, TypeAccessSemantics::Reference, sourceId1, - {Storage::ExportedType{"Object", Storage::Version{}}}, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{}}}, {Storage::PropertyDeclaration{"data", - Storage::NativeType{"QObject"}, + Storage::ImportedType{"Object"}, Storage::PropertyDeclarationTraits::IsList}}}; - Storage::Import import{"Qml", Storage::Version{}, sourceId1}; - storage.synchronize(modules, - {import}, + Storage::Import import{qmlModuleId, Storage::Version{}, sourceId1}; + storage.synchronize({import}, {type}, {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - ASSERT_NO_THROW(storage.synchronize({}, {}, {}, {sourceId1}, {})); + ASSERT_NO_THROW(storage.synchronize({}, {}, {sourceId1}, {})); } TEST_F(ProjectStorage, EnsureThatPrototypesForRemovedTypesAreNotAnymoreRelinked) { auto types = createTypes(); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - ASSERT_NO_THROW(storage.synchronize({}, {}, {}, {sourceId1, sourceId2}, {})); + ASSERT_NO_THROW(storage.synchronize({}, {}, {sourceId1, sourceId2}, {})); } TEST_F(ProjectStorage, MinimalUpdates) { auto types = createTypes(); storage.synchronize( - modules, imports, types, {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, {}); - Storage::Type quickType{qtQuickModuleId, - "QQuickItem", + Storage::Type quickType{"QQuickItem", {}, TypeAccessSemantics::Reference, sourceId1, - {Storage::ExportedType{"Item", Storage::Version{2, 0}}}, + {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{2, 0}}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}, {}, {}, {}, {}, Storage::ChangeLevel::Minimal}; - storage.synchronize({modules[1]}, {}, {quickType}, {qtQuickModuleSourceId}, {}); + storage.synchronize({}, {quickType}, {}, {}); - ASSERT_THAT(storage.fetchTypes(), - UnorderedElementsAre(AllOf(IsStorageType(qmlModuleId, - "QObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId2), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Object"), - IsExportedType("Obj")))), - AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::exportedTypes, - UnorderedElementsAre(IsExportedType("Item", 2, 0)))))); + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item", 2, 0), + IsExportedType(qtQuickNativeModuleId, "QQuickItem"))), + Field(&Storage::Type::propertyDeclarations, Not(IsEmpty())), + Field(&Storage::Type::functionDeclarations, Not(IsEmpty())), + Field(&Storage::Type::signalDeclarations, Not(IsEmpty())), + Field(&Storage::Type::enumerationDeclarations, Not(IsEmpty()))))); +} + +TEST_F(ProjectStorage, GetModuleId) +{ + auto id = storage.moduleId("Qml"); + + ASSERT_TRUE(id); +} + +TEST_F(ProjectStorage, GetSameModuleIdAgain) +{ + auto initialId = storage.moduleId("Qml"); + + auto id = storage.moduleId("Qml"); + + ASSERT_THAT(id, Eq(initialId)); +} + +TEST_F(ProjectStorage, ModuleNameThrowsIfIdIsInvalid) +{ + ASSERT_THROW(storage.moduleName(ModuleId{}), QmlDesigner::ModuleDoesNotExists); +} + +TEST_F(ProjectStorage, ModuleNameThrowsIfIdDoesNotExists) +{ + ASSERT_THROW(storage.moduleName(ModuleId{222}), QmlDesigner::ModuleDoesNotExists); +} + +TEST_F(ProjectStorage, GetModuleName) +{ + auto id = storage.moduleId("Qml"); + + auto name = storage.moduleName(id); + + ASSERT_THAT(name, Eq("Qml")); +} + +TEST_F(ProjectStorage, PopulateModuleCache) +{ + auto id = storage.moduleId("Qml"); + + QmlDesigner::ProjectStorage newStorage{database, database.isInitialized()}; + + ASSERT_THAT(newStorage.moduleName(id), Eq("Qml")); } } // namespace diff --git a/tests/unit/unittest/projectstoragemock.h b/tests/unit/unittest/projectstoragemock.h index 6fecc58ad45..0f4c40e56e4 100644 --- a/tests/unit/unittest/projectstoragemock.h +++ b/tests/unit/unittest/projectstoragemock.h @@ -38,13 +38,14 @@ class ProjectStorageMock : public QmlDesigner::ProjectStorageInterface public: MOCK_METHOD(void, synchronize, - (QmlDesigner::Storage::Modules modules, - QmlDesigner::Storage::Imports imports, + (QmlDesigner::Storage::Imports imports, QmlDesigner::Storage::Types types, QmlDesigner::SourceIds sourceIds, QmlDesigner::FileStatuses fileStatuses), (override)); + MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (Utils::SmallStringView), (override)); + MOCK_METHOD(QmlDesigner::FileStatus, fetchFileStatus, (QmlDesigner::SourceId sourceId), diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp index d6a26bb1094..2b70d332c7d 100644 --- a/tests/unit/unittest/projectstorageupdater-test.cpp +++ b/tests/unit/unittest/projectstorageupdater-test.cpp @@ -42,26 +42,25 @@ namespace { namespace Storage = QmlDesigner::Storage; using QmlDesigner::FileStatus; +using QmlDesigner::ModuleId; using QmlDesigner::SourceId; using QmlDesigner::Storage::TypeAccessSemantics; namespace Storage = QmlDesigner::Storage; using QmlDesigner::IdPaths; using QmlDesigner::Storage::Version; -MATCHER_P5(IsStorageType, - moduleId, +MATCHER_P4(IsStorageType, typeName, prototype, accessSemantics, sourceId, std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::Type{moduleId, typeName, prototype, accessSemantics, sourceId})) + + PrintToString(Storage::Type{typeName, prototype, accessSemantics, sourceId})) { const Storage::Type &type = arg; - return type.moduleId == moduleId && type.typeName == typeName - && type.accessSemantics == accessSemantics && type.sourceId == sourceId - && Storage::ImportedTypeName{prototype} == type.prototype; + return type.typeName == typeName && type.accessSemantics == accessSemantics + && type.sourceId == sourceId && Storage::ImportedTypeName{prototype} == type.prototype; } MATCHER_P3(IsPropertyDeclaration, @@ -78,27 +77,20 @@ MATCHER_P3(IsPropertyDeclaration, && propertyDeclaration.traits == traits; } -MATCHER_P3(IsExportedType, +MATCHER_P4(IsExportedType, + moduleId, name, majorVersion, minorVersion, std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::ExportedType{name, + + PrintToString(Storage::ExportedType{moduleId, + name, Storage::Version{majorVersion, minorVersion}})) { const Storage::ExportedType &type = arg; - return type.name == name && type.version == Storage::Version{majorVersion, minorVersion}; -} - -MATCHER_P2(IsModule, - name, - sourceId, - std::string(negation ? "isn't " : "is ") + PrintToString(Storage::Module{name, sourceId})) -{ - const Storage::Module &module = arg; - - return module.name == name && module.sourceId == sourceId; + return type.moduleId == moduleId && type.name == name + && type.version == Storage::Version{majorVersion, minorVersion}; } MATCHER_P3(IsFileStatus, @@ -154,6 +146,8 @@ public: .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14})); ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3))) .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 2})); + ON_CALL(projectStorageMock, moduleId(Eq("Example"))).WillByDefault(Return(exampleModuleId)); + ON_CALL(projectStorageMock, moduleId(Eq("Qml"))).WillByDefault(Return(qmlModuleId)); firstType.prototype = Storage::ImportedType{"Object"}; secondType.prototype = Storage::ImportedType{"Object2"}; @@ -203,25 +197,26 @@ protected: SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes"); SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/example2.qmltypes"); SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir"); - QmlDesigner::ModuleId exampleModuleId{&qmlDirPathSourceId}; SourceId qmlDocumentSourceId1 = sourcePathCache.sourceId("/path/First.qml"); SourceId qmlDocumentSourceId2 = sourcePathCache.sourceId("/path/First.2.qml"); SourceId qmlDocumentSourceId3 = sourcePathCache.sourceId("/path/Second.qml"); - Storage::Type objectType{exampleModuleId, - "QObject", + ModuleId qmlModuleId{storage.moduleId("Qml")}; + ModuleId exampleModuleId{storage.moduleId("Example")}; + Storage::Type objectType{"QObject", Storage::NativeType{}, Storage::TypeAccessSemantics::Reference, objectTypeSourceId, - {Storage::ExportedType{"Object"}, Storage::ExportedType{"Obj"}}}; + {Storage::ExportedType{exampleModuleId, "Object"}, + Storage::ExportedType{exampleModuleId, "Obj"}}}; QString qmlDocument1{"First{}"}; QString qmlDocument2{"Second{}"}; QString qmlDocument3{"Third{}"}; Storage::Type firstType; Storage::Type secondType; Storage::Type thirdType; - Storage::Import import1{"Qml", Storage::Version{2, 3}, qmlDocumentSourceId1}; - Storage::Import import2{"Qml", Storage::Version{}, qmlDocumentSourceId2}; - Storage::Import import3{"Qml", Storage::Version{2}, qmlDocumentSourceId3}; + Storage::Import import1{qmlModuleId, Storage::Version{2, 3}, qmlDocumentSourceId1}; + Storage::Import import2{qmlModuleId, Storage::Version{}, qmlDocumentSourceId2}; + Storage::Import import3{qmlModuleId, Storage::Version{2}, qmlDocumentSourceId3}; }; TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent) @@ -320,8 +315,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange) ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId))) .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421})); - EXPECT_CALL(projectStorageMock, - synchronize(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty())); + EXPECT_CALL(projectStorageMock, synchronize(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty())); updater.update(); } @@ -330,7 +324,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes) { auto qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir"); auto qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes"); - Storage::Import import{"Qml", Storage::Version{2, 3}, qmltypesPathSourceId}; + Storage::Import import{qmlModuleId, Storage::Version{2, 3}, qmltypesPathSourceId}; QString qmltypes{"Module {\ndependencies: []}"}; ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) .WillByDefault(Return(qmltypes)); @@ -340,9 +334,9 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes) imports.push_back(import); }); + EXPECT_CALL(projectStorageMock, moduleId(Eq("Example"))); EXPECT_CALL(projectStorageMock, - synchronize(ElementsAre(IsModule("Example", qmlDirPathSourceId)), - ElementsAre(import), + synchronize(ElementsAre(import), ElementsAre(Eq(objectType)), UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId), UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), @@ -366,8 +360,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged) ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId))) .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421})); - EXPECT_CALL(projectStorageMock, - synchronize(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty())); + EXPECT_CALL(projectStorageMock, synchronize(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty())); updater.update(); } @@ -414,39 +407,36 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments) "First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"}; ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); - EXPECT_CALL(projectStorageMock, - synchronize(ElementsAre(IsModule("Example", qmlDirPathSourceId)), - UnorderedElementsAre(import1, import2, import3), - UnorderedElementsAre( - AllOf(IsStorageType(exampleModuleId, - "First.qml", - Storage::ImportedType{"Object"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId1), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType("FirstType", 1, 0)))), - AllOf(IsStorageType(exampleModuleId, - "First.2.qml", - Storage::ImportedType{"Object2"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId2), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType("FirstType", 2, 2)))), - AllOf(IsStorageType(exampleModuleId, - "Second.qml", - Storage::ImportedType{"Object3"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId3), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType("SecondType", 2, 2))))), - UnorderedElementsAre(qmlDirPathSourceId, - qmlDocumentSourceId1, - qmlDocumentSourceId2, - qmlDocumentSourceId3), - UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), - IsFileStatus(qmlDocumentSourceId1, 22, 12), - IsFileStatus(qmlDocumentSourceId2, 22, 13), - IsFileStatus(qmlDocumentSourceId3, 22, 14)))); + EXPECT_CALL( + projectStorageMock, + synchronize(UnorderedElementsAre(import1, import2, import3), + UnorderedElementsAre( + AllOf(IsStorageType("First.qml", + Storage::ImportedType{"Object"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId1), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), + AllOf(IsStorageType("First.2.qml", + Storage::ImportedType{"Object2"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId2), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))), + AllOf(IsStorageType("Second.qml", + Storage::ImportedType{"Object3"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId3), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2))))), + UnorderedElementsAre(qmlDirPathSourceId, + qmlDocumentSourceId1, + qmlDocumentSourceId2, + qmlDocumentSourceId3), + UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), + IsFileStatus(qmlDocumentSourceId1, 22, 12), + IsFileStatus(qmlDocumentSourceId2, 22, 13), + IsFileStatus(qmlDocumentSourceId3, 22, 14)))); updater.update(); } @@ -461,22 +451,20 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate) EXPECT_CALL( projectStorageMock, - synchronize(ElementsAre(IsModule("Example", qmlDirPathSourceId)), - UnorderedElementsAre(import1, import2), - UnorderedElementsAre(AllOf(IsStorageType(exampleModuleId, - "First.qml", - Storage::ImportedType{"Object"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId1), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType("FirstType", 1, 0)))), - AllOf(IsStorageType(exampleModuleId, - "First.2.qml", - Storage::ImportedType{"Object2"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId2), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType("FirstType", 2, 2))))), + synchronize(UnorderedElementsAre(import1, import2), + UnorderedElementsAre( + AllOf(IsStorageType("First.qml", + Storage::ImportedType{"Object"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId1), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), + AllOf(IsStorageType("First.2.qml", + Storage::ImportedType{"Object2"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId2), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2))))), UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2), UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), IsFileStatus(qmlDocumentSourceId1, 22, 12), @@ -485,31 +473,6 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate) updater.update(); } -TEST_F(ProjectStorageUpdater, SynchronizeModules) -{ - SourceId qmlDirPathSourceId2 = sourcePathCache.sourceId("/path2/qmldir"); - ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId2))) - .WillByDefault(Return(FileStatus{qmlDirPathSourceId2, 22, 423})); - ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId2))) - .WillByDefault(Return(FileStatus{qmlDirPathSourceId2, 2, 421})); - QString qmldir2{"module Example2\n"}; - ON_CALL(projectManagerMock, qtQmlDirs()) - .WillByDefault(Return(QStringList{"/path/qmldir", "/path2/qmldir"})); - ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path2/qmldir")))).WillByDefault(Return(qmldir2)); - - EXPECT_CALL(projectStorageMock, - synchronize(UnorderedElementsAre(IsModule("Example", qmlDirPathSourceId), - IsModule("Example2", qmlDirPathSourceId2)), - _, - _, - _, - UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), - IsFileStatus(qmltypesPathSourceId, 21, 421), - IsFileStatus(qmlDirPathSourceId2, 22, 423)))); - - updater.update(); -} - TEST_F(ProjectStorageUpdater, UpdateQmldirDocuments) { QString qmldir{"module Example\nFirstType 1.1 First.qml\nFirstType 2.2 " diff --git a/tests/unit/unittest/qmldocumentparser-test.cpp b/tests/unit/unittest/qmldocumentparser-test.cpp index 4cadf8253d7..451003ba33c 100644 --- a/tests/unit/unittest/qmldocumentparser-test.cpp +++ b/tests/unit/unittest/qmldocumentparser-test.cpp @@ -129,7 +129,7 @@ protected: QmlDesigner::ProjectStorage storage{database, database.isInitialized()}; QmlDesigner::SourcePathCache> sourcePathCache{ storage}; - QmlDesigner::QmlDocumentParser parser{sourcePathCache}; + QmlDesigner::QmlDocumentParser parser{sourcePathCache, storage}; Storage::Imports imports; SourceId qmlFileSourceId{sourcePathCache.sourceId("path/to/qmlfile.qml")}; SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)}; @@ -146,6 +146,7 @@ TEST_F(QmlDocumentParser, Prototype) TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype) { + auto exampleModuleId = storage.moduleId("Example"); auto type = parser.parse("import Example as Example\n Example.Item{}", imports, qmlFileSourceId, @@ -153,7 +154,7 @@ TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype) ASSERT_THAT(type, HasPrototype(Storage::QualifiedImportedType( - "Item", Storage::Import{"Example", Storage::Version{}, qmlFileSourceId}))); + "Item", Storage::Import{exampleModuleId, Storage::Version{}, qmlFileSourceId}))); } TEST_F(QmlDocumentParser, Properties) @@ -171,7 +172,10 @@ TEST_F(QmlDocumentParser, Properties) TEST_F(QmlDocumentParser, DISABLED_Imports) { - ModuleId fooDirectoryModuleId{&sourcePathCache.sourceId("path/to/foo/.")}; + ModuleId fooDirectoryModuleId = storage.moduleId("path/to/foo/."); + ModuleId qmlModuleId = storage.moduleId("QML"); + ModuleId qtQmlModuleId = storage.moduleId("QtQml"); + ModuleId qtQuickModuleId = storage.moduleId("QtQuick"); auto type = parser.parse("import QtQuick\n import \"../foo\"\nExample{}", imports, qmlFileSourceId, @@ -179,11 +183,11 @@ TEST_F(QmlDocumentParser, DISABLED_Imports) ASSERT_THAT(imports, UnorderedElementsAre( - Storage::Import{Storage::Version{}, directoryModuleId, qmlFileSourceId}, - Storage::Import{Storage::Version{}, fooDirectoryModuleId, qmlFileSourceId}, - Storage::Import{"QML", Storage::Version{1, 0}, qmlFileSourceId}, - Storage::Import{"QtQml", Storage::Version{6, 0}, qmlFileSourceId}, - Storage::Import{"QtQuick", Storage::Version{}, qmlFileSourceId})); + Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId}, + Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId}, + Storage::Import{qmlModuleId, Storage::Version{1, 0}, qmlFileSourceId}, + Storage::Import{qtQmlModuleId, Storage::Version{6, 0}, qmlFileSourceId}, + Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId})); } TEST_F(QmlDocumentParser, Functions) diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp index fcd182b9206..8fd4263d223 100644 --- a/tests/unit/unittest/qmltypesparser-test.cpp +++ b/tests/unit/unittest/qmltypesparser-test.cpp @@ -39,18 +39,16 @@ using QmlDesigner::ModuleId; using QmlDesigner::SourceContextId; using QmlDesigner::SourceId; -MATCHER_P4(IsImport, - name, +MATCHER_P3(IsImport, + moduleId, version, sourceId, - kind, std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::Import{name, version, sourceId, kind})) + + PrintToString(Storage::Import{moduleId, version, sourceId})) { const Storage::Import &import = arg; - return import.name == name && import.version == version && import.sourceId == sourceId - && import.kind == kind; + return import.moduleId == moduleId && import.version == version && import.sourceId == sourceId; } MATCHER_P(HasPrototype, prototype, std::string(negation ? "isn't " : "is ") + PrintToString(prototype)) @@ -60,19 +58,17 @@ MATCHER_P(HasPrototype, prototype, std::string(negation ? "isn't " : "is ") + Pr return Storage::ImportedTypeName{prototype} == type.prototype; } -MATCHER_P5(IsType, - moduleId, +MATCHER_P4(IsType, typeName, prototype, accessSemantics, sourceId, std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::Type{moduleId, typeName, prototype, accessSemantics, sourceId})) + + PrintToString(Storage::Type{typeName, prototype, accessSemantics, sourceId})) { const Storage::Type &type = arg; - return type.moduleId == moduleId && type.typeName == typeName - && type.prototype == Storage::ImportedTypeName{prototype} + return type.typeName == typeName && type.prototype == Storage::ImportedTypeName{prototype} && type.accessSemantics == accessSemantics && type.sourceId == sourceId; } @@ -173,13 +169,12 @@ protected: QmlDesigner::ProjectStorage storage{database, database.isInitialized()}; QmlDesigner::SourcePathCache> sourcePathCache{ storage}; - QmlDesigner::QmlTypesParser parser{sourcePathCache}; + QmlDesigner::QmlTypesParser parser{sourcePathCache, storage}; Storage::Imports imports; Storage::Types types; SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")}; SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)}; - SourceId directorySourceId{sourcePathCache.sourceId("path/to/.")}; - ModuleId directoryModuleId{&directorySourceId}; + ModuleId directoryModuleId{storage.moduleId("path/to/")}; }; TEST_F(QmlTypesParser, Imports) @@ -191,27 +186,20 @@ TEST_F(QmlTypesParser, Imports) parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); - ASSERT_THAT(imports, - UnorderedElementsAre(IsImport("QtQuick", - Storage::Version{2, 15}, - qmltypesFileSourceId, - Storage::ImportKind::QmlTypesDependency), - IsImport("QtQuick.Window", - Storage::Version{2, 1}, - qmltypesFileSourceId, - Storage::ImportKind::QmlTypesDependency), - IsImport("QML", - Storage::Version{}, - qmltypesFileSourceId, - Storage::ImportKind::QmlTypesDependency), - IsImport("QtQml", - Storage::Version{}, - qmltypesFileSourceId, - Storage::ImportKind::QmlTypesDependency), - IsImport("QtFoo", - Storage::Version{6}, - qmltypesFileSourceId, - Storage::ImportKind::QmlTypesDependency))); + ASSERT_THAT( + imports, + UnorderedElementsAre( + IsImport(storage.moduleId("QML"), Storage::Version{}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQml"), Storage::Version{}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQml-cppnative"), Storage::Version{}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQuick"), Storage::Version{2, 15}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQuick-cppnative"), Storage::Version{2, 15}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQuick.Window"), Storage::Version{2, 1}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQuick.Window-cppnative"), + Storage::Version{2, 1}, + qmltypesFileSourceId), + IsImport(storage.moduleId("QtFoo"), Storage::Version{6}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtFoo-cppnative"), Storage::Version{6}, qmltypesFileSourceId))); } TEST_F(QmlTypesParser, Types) @@ -225,13 +213,11 @@ TEST_F(QmlTypesParser, Types) parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); ASSERT_THAT(types, - UnorderedElementsAre(IsType(directoryModuleId, - "QObject", + UnorderedElementsAre(IsType("QObject", Storage::NativeType{}, Storage::TypeAccessSemantics::Reference, qmltypesFileSourceId), - IsType(directoryModuleId, - "QQmlComponent", + IsType("QQmlComponent", Storage::NativeType{"QObject"}, Storage::TypeAccessSemantics::Reference, qmltypesFileSourceId))); From b4fcd05451dd35fd2f3abb0b73a66c82327d22fb Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 19 Oct 2021 14:42:28 +0200 Subject: [PATCH 114/117] QmlDesigner: Introduce different modules for cpp, qml and directories There are now different modules for qml, cpp and directory imports. Cpp imports are qml import append by "-cppnative". Task-number: QDS-5196 Change-Id: I599b224892c5ada0224a765d0bde8b32de20b061 Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Bot --- .../projectstorage/projectstorage.h | 5 ++- .../projectstorage/projectstorageinterface.h | 2 +- .../projectstorage/projectstoragetypes.h | 9 +++++ .../projectstorage/projectstorageupdater.cpp | 38 ++++++++----------- .../projectstorage/projectstorageupdater.h | 7 +--- .../projectstorage/qmltypesparser.cpp | 37 +++++++++--------- .../projectstorage/qmltypesparser.h | 3 +- .../projectstorage/qmltypesparserinterface.h | 3 +- tests/unit/unittest/projectstoragemock.h | 4 +- .../unittest/projectstorageupdater-test.cpp | 19 +++++----- tests/unit/unittest/qmltypesparser-test.cpp | 37 +++++++++--------- tests/unit/unittest/qmltypesparsermock.h | 3 +- 12 files changed, 86 insertions(+), 81 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index f6412d231b4..2e7b0629cc5 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -308,7 +308,10 @@ public: &sourceId); } - SourceIds fetchSourceDependencieIds(SourceId sourceId) const override { return {}; } + Storage::ProjectDatas fetchProjectDatas(SourceId sourceId) const override + { + return Storage::ProjectDatas{}; + } private: class ModuleStorageAdapter diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h index 4eaa0527d23..219c6137a10 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h @@ -42,7 +42,7 @@ public: virtual ModuleId moduleId(Utils::SmallStringView name) = 0; virtual FileStatus fetchFileStatus(SourceId sourceId) const = 0; - virtual SourceIds fetchSourceDependencieIds(SourceId sourceId) const = 0; + virtual Storage::ProjectDatas fetchProjectDatas(SourceId sourceId) const = 0; protected: ~ProjectStorageInterface() = default; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index ffbfe7364cb..43a0109a6ad 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -717,4 +717,13 @@ public: using Types = std::vector; +class ProjectData +{ +public: + ModuleId extraModuleId; + SourceId sourceId; +}; + +using ProjectDatas = std::vector; + } // namespace QmlDesigner::Storage diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp index 5a23b699448..83fc1399ab9 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp @@ -70,10 +70,10 @@ void ProjectUpdater::update() SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId); - ModuleId moduleId = m_projectStorage.moduleId(Utils::PathString{parser.typeNamespace()}); + Utils::PathString moduleName{parser.typeNamespace()}; + ModuleId moduleId = m_projectStorage.moduleId(moduleName); - parseTypeInfos( - parser.typeInfos(), directoryId, moduleId, imports, types, sourceIds, fileStatuses); + parseTypeInfos(parser.typeInfos(), directoryId, imports, types, sourceIds, fileStatuses); parseQmlComponents(createComponentReferences(parser.components()), directoryId, moduleId, @@ -84,13 +84,8 @@ void ProjectUpdater::update() break; } case FileState::NotChanged: { - SourceIds qmltypesSourceIds = m_projectStorage.fetchSourceDependencieIds(qmlDirSourceId); - parseTypeInfos(ModuleId{&qmlDirSourceId}, - qmltypesSourceIds, - imports, - types, - sourceIds, - fileStatuses); + auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId); + parseTypeInfos(qmlProjectDatas, imports, types, sourceIds, fileStatuses); break; } case FileState::NotExists: { @@ -110,7 +105,6 @@ void ProjectUpdater::pathsWithIdsChanged(const std::vector &idPaths) {} void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, SourceContextId directoryId, - ModuleId moduleId, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, @@ -122,36 +116,36 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo}); QString qmltypesPath = directory + "/" + typeInfo; - parseTypeInfo(sourceId, moduleId, qmltypesPath, imports, types, sourceIds, fileStatuses); + Storage::ProjectData projectData{ModuleId{}, sourceId}; + + parseTypeInfo(projectData, qmltypesPath, imports, types, sourceIds, fileStatuses); } } -void ProjectUpdater::parseTypeInfos(ModuleId moduleId, - const SourceIds &qmltypesSourceIds, +void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, FileStatuses &fileStatuses) { - for (SourceId sourceId : qmltypesSourceIds) { - QString qmltypesPath = m_pathCache.sourcePath(sourceId).toQString(); + for (const Storage::ProjectData &projectData : projectDatas) { + QString qmltypesPath = m_pathCache.sourcePath(projectData.sourceId).toQString(); - parseTypeInfo(sourceId, moduleId, qmltypesPath, imports, types, sourceIds, fileStatuses); + parseTypeInfo(projectData, qmltypesPath, imports, types, sourceIds, fileStatuses); } } -void ProjectUpdater::parseTypeInfo(SourceId sourceId, - ModuleId moduleId, +void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData, const QString &qmltypesPath, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, FileStatuses &fileStatuses) { - if (fileState(sourceId, fileStatuses) == FileState::Changed) { - sourceIds.push_back(sourceId); + if (fileState(projectData.sourceId, fileStatuses) == FileState::Changed) { + sourceIds.push_back(projectData.sourceId); const auto content = m_fileSystem.contentAsQString(qmltypesPath); - m_qmlTypesParser.parse(content, imports, types, sourceId, moduleId); + m_qmlTypesParser.parse(content, imports, types, projectData); } } diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h index ce611b71412..2ef61aaaf97 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h @@ -88,19 +88,16 @@ private: void parseTypeInfos(const QStringList &typeInfos, SourceContextId directoryId, - ModuleId moduleId, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, FileStatuses &fileStatuses); - void parseTypeInfos(ModuleId moduleId, - const SourceIds &qmltypesSourceIds, + void parseTypeInfos(const Storage::ProjectDatas &projectDatas, Storage::Imports &imports, Storage::Types &types, SourceIds &sourceIds, FileStatuses &fileStatuses); - void parseTypeInfo(SourceId sourceId, - ModuleId moduleId, + void parseTypeInfo(const Storage::ProjectData &projectData, const QString &qmltypesPath, Storage::Imports &imports, Storage::Types &types, diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp index e3942653218..f5d09409aa3 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp @@ -43,7 +43,6 @@ namespace QmlDesigner { namespace QmlDom = QQmlJS::Dom; namespace { -void addType(const QQmlJSScope::Ptr &object, Storage::Types &types) {} void appendImports(Storage::Imports &imports, const QString &dependency, @@ -55,8 +54,6 @@ void appendImports(Storage::Imports &imports, }); Utils::PathString moduleName{QStringView(dependency.begin(), spaceFound)}; - ModuleId moduleId = storage.moduleId(moduleName); - moduleName.append("-cppnative"); ModuleId cppModuleId = storage.moduleId(moduleName); @@ -84,7 +81,6 @@ void appendImports(Storage::Imports &imports, version.minor.value = QStringView(minorVersionFound, minorVersionEnd).toInt(); } - imports.emplace_back(moduleId, version, sourceId); imports.emplace_back(cppModuleId, version, sourceId); } @@ -97,7 +93,6 @@ void addImports(Storage::Imports &imports, appendImports(imports, dependency, sourceId, storage); imports.emplace_back(storage.moduleId("QML"), Storage::Version{}, sourceId); - imports.emplace_back(storage.moduleId("QtQml"), Storage::Version{}, sourceId); imports.emplace_back(storage.moduleId("QtQml-cppnative"), Storage::Version{}, sourceId); } @@ -122,17 +117,22 @@ Storage::Version createVersion(QTypeRevision qmlVersion) return Storage::Version{qmlVersion.majorVersion(), qmlVersion.minorVersion()}; } -Storage::ExportedTypes createExports(ModuleId moduleId, const QList &qmlExports) +Storage::ExportedTypes createExports(const QList &qmlExports, + const QQmlJSScope &component, + QmlTypesParser::ProjectStorage &storage, + ModuleId cppModuleId) { Storage::ExportedTypes exportedTypes; exportedTypes.reserve(Utils::usize(qmlExports)); for (const QQmlJSScope::Export &qmlExport : qmlExports) { - exportedTypes.emplace_back(moduleId, + exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()}), Utils::SmallString{qmlExport.type()}, createVersion(qmlExport.version())); } + exportedTypes.emplace_back(cppModuleId, Utils::SmallString{component.internalName()}); + return exportedTypes; } @@ -257,14 +257,18 @@ Storage::EnumerationDeclarations createEnumeration(const QHash &objects) + const Storage::ProjectData &projectData, + const QHash &objects, + QmlTypesParser::ProjectStorage &storage) { types.reserve(Utils::usize(objects) + types.size()); for (const auto &object : objects) - addType(types, sourceId, moduleId, *object.get()); + addType(types, projectData.sourceId, projectData.extraModuleId, *object.get(), storage); } } // namespace @@ -287,8 +291,7 @@ void addTypes(Storage::Types &types, void QmlTypesParser::parse(const QString &sourceContent, Storage::Imports &imports, Storage::Types &types, - SourceId sourceId, - ModuleId moduleId) + const Storage::ProjectData &projectData) { QQmlJSTypeDescriptionReader reader({}, sourceContent); QHash components; @@ -297,8 +300,8 @@ void QmlTypesParser::parse(const QString &sourceContent, if (!isValid) throw CannotParseQmlTypesFile{}; - addImports(imports, sourceId, dependencies, m_storage); - addTypes(types, sourceId, moduleId, components); + addImports(imports, projectData.sourceId, dependencies, m_storage); + addTypes(types, projectData, components, m_storage); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h index eeb58f0e318..40f88d240dc 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h @@ -54,8 +54,7 @@ public: void parse(const QString &sourceContent, Storage::Imports &imports, Storage::Types &types, - SourceId sourceId, - ModuleId moduleId) override; + const Storage::ProjectData &projectData) override; private: PathCache &m_pathCache; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h index d3b102954c0..3255c0b5aac 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h @@ -37,8 +37,7 @@ public: virtual void parse(const QString &sourceContent, Storage::Imports &imports, Storage::Types &types, - SourceId sourceId, - ModuleId moduleId) + const Storage::ProjectData &projectData) = 0; protected: diff --git a/tests/unit/unittest/projectstoragemock.h b/tests/unit/unittest/projectstoragemock.h index 0f4c40e56e4..161a2a0fe1b 100644 --- a/tests/unit/unittest/projectstoragemock.h +++ b/tests/unit/unittest/projectstoragemock.h @@ -51,8 +51,8 @@ public: (QmlDesigner::SourceId sourceId), (const, override)); - MOCK_METHOD(QmlDesigner::SourceIds, - fetchSourceDependencieIds, + MOCK_METHOD(QmlDesigner::Storage::ProjectDatas, + fetchProjectDatas, (QmlDesigner::SourceId sourceId), (const, override)); diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp index 2b70d332c7d..d63448063d4 100644 --- a/tests/unit/unittest/projectstorageupdater-test.cpp +++ b/tests/unit/unittest/projectstorageupdater-test.cpp @@ -126,8 +126,10 @@ public: ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId))) .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421})); - ON_CALL(projectStorageMock, fetchSourceDependencieIds(Eq(qmlDirPathSourceId))) - .WillByDefault(Return(QmlDesigner::SourceIds{qmltypesPathSourceId, qmltypes2PathSourceId})); + ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId))) + .WillByDefault( + Return(QmlDesigner::Storage::ProjectDatas{{ModuleId{}, qmltypesPathSourceId}, + {ModuleId{}, qmltypes2PathSourceId}})); QString qmldir{"module Example\ntypeinfo example.qmltypes\n"}; ON_CALL(projectManagerMock, qtQmlDirs()).WillByDefault(Return(QStringList{"/path/qmldir"})); @@ -300,8 +302,8 @@ TEST_F(ProjectStorageUpdater, ParseQmlTypes) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example2.qmltypes")))) .WillByDefault(Return(qmltypes2)); - EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)); - EXPECT_CALL(qmlTypesParserMock, parse(qmltypes2, _, _, _, _)); + EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)); + EXPECT_CALL(qmlTypesParserMock, parse(qmltypes2, _, _, _)); updater.update(); } @@ -328,8 +330,8 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes) QString qmltypes{"Module {\ndependencies: []}"}; ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) .WillByDefault(Return(qmltypes)); - ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)) - .WillByDefault([&](auto, auto &imports, auto &types, auto, auto) { + ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)) + .WillByDefault([&](auto, auto &imports, auto &types, auto) { types.push_back(objectType); imports.push_back(import); }); @@ -350,9 +352,8 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged) QString qmltypes{"Module {\ndependencies: []}"}; ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) .WillByDefault(Return(qmltypes)); - ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)) - .WillByDefault( - [&](auto, auto &imports, auto &types, auto, auto) { types.push_back(objectType); }); + ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)) + .WillByDefault([&](auto, auto &, auto &types, auto) { types.push_back(objectType); }); ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId))) .WillByDefault(Return(FileStatus{qmltypesPathSourceId, 2, 421})); ON_CALL(fileSystemMock, fileStatus(Eq(qmltypes2PathSourceId))) diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp index 8fd4263d223..9de60a1807f 100644 --- a/tests/unit/unittest/qmltypesparser-test.cpp +++ b/tests/unit/unittest/qmltypesparser-test.cpp @@ -173,6 +173,8 @@ protected: Storage::Imports imports; Storage::Types types; SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")}; + QmlDesigner::Storage::ProjectData projectData{storage.moduleId("QtQml-cppnative"), + qmltypesFileSourceId}; SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)}; ModuleId directoryModuleId{storage.moduleId("path/to/")}; }; @@ -184,21 +186,17 @@ TEST_F(QmlTypesParser, Imports) dependencies: ["QtQuick 2.15", "QtQuick.Window 2.1", "QtFoo 6"]})"}; - parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + parser.parse(source, imports, types, projectData); ASSERT_THAT( imports, UnorderedElementsAre( IsImport(storage.moduleId("QML"), Storage::Version{}, qmltypesFileSourceId), - IsImport(storage.moduleId("QtQml"), Storage::Version{}, qmltypesFileSourceId), IsImport(storage.moduleId("QtQml-cppnative"), Storage::Version{}, qmltypesFileSourceId), - IsImport(storage.moduleId("QtQuick"), Storage::Version{2, 15}, qmltypesFileSourceId), IsImport(storage.moduleId("QtQuick-cppnative"), Storage::Version{2, 15}, qmltypesFileSourceId), - IsImport(storage.moduleId("QtQuick.Window"), Storage::Version{2, 1}, qmltypesFileSourceId), IsImport(storage.moduleId("QtQuick.Window-cppnative"), Storage::Version{2, 1}, qmltypesFileSourceId), - IsImport(storage.moduleId("QtFoo"), Storage::Version{6}, qmltypesFileSourceId), IsImport(storage.moduleId("QtFoo-cppnative"), Storage::Version{6}, qmltypesFileSourceId))); } @@ -210,7 +208,7 @@ TEST_F(QmlTypesParser, Types) Component { name: "QQmlComponent" prototype: "QObject"}})"}; - parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + parser.parse(source, imports, types, projectData); ASSERT_THAT(types, UnorderedElementsAre(IsType("QObject", @@ -228,17 +226,20 @@ TEST_F(QmlTypesParser, ExportedTypes) QString source{R"(import QtQuick.tooling 1.2 Module{ Component { name: "QObject" - exports: ["QtQml/QtObject 1.0", "QtQml/QtObject 2.1"] + exports: ["QML/QtObject 1.0", "QtQml/QtObject 2.1"] }})"}; + ModuleId qmlModuleId = storage.moduleId("QML"); + ModuleId qtQmlModuleId = storage.moduleId("QtQml"); + ModuleId qtQmlNativeModuleId = storage.moduleId("QtQml-cppnative"); - parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + parser.parse(source, imports, types, projectData); - ASSERT_THAT( - types, - ElementsAre( - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType(directoryModuleId, "QtObject", Storage::Version{1, 0}), - IsExportedType(directoryModuleId, "QtObject", Storage::Version{2, 1}))))); + ASSERT_THAT(types, + ElementsAre(Field( + &Storage::Type::exportedTypes, + ElementsAre(IsExportedType(qmlModuleId, "QtObject", Storage::Version{1, 0}), + IsExportedType(qtQmlModuleId, "QtObject", Storage::Version{2, 1}), + IsExportedType(qtQmlNativeModuleId, "QObject", Storage::Version{}))))); } TEST_F(QmlTypesParser, Properties) @@ -252,7 +253,7 @@ TEST_F(QmlTypesParser, Properties) Property { name: "targets"; type: "QQuickItem"; isList: true; isReadonly: true; isPointer: true } }})"}; - parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + parser.parse(source, imports, types, projectData); ASSERT_THAT(types, ElementsAre(Field( @@ -296,7 +297,7 @@ TEST_F(QmlTypesParser, Functions) } }})"}; - parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + parser.parse(source, imports, types, projectData); ASSERT_THAT(types, ElementsAre( @@ -337,7 +338,7 @@ TEST_F(QmlTypesParser, Signals) } }})"}; - parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + parser.parse(source, imports, types, projectData); ASSERT_THAT(types, ElementsAre(Field(&Storage::Type::signalDeclarations, @@ -375,7 +376,7 @@ TEST_F(QmlTypesParser, Enumerations) } }})"}; - parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId); + parser.parse(source, imports, types, projectData); ASSERT_THAT(types, ElementsAre( diff --git a/tests/unit/unittest/qmltypesparsermock.h b/tests/unit/unittest/qmltypesparsermock.h index cfbb8729841..6cf52713797 100644 --- a/tests/unit/unittest/qmltypesparsermock.h +++ b/tests/unit/unittest/qmltypesparsermock.h @@ -37,7 +37,6 @@ public: (const QString &sourceContent, QmlDesigner::Storage::Imports &imports, QmlDesigner::Storage::Types &types, - QmlDesigner::SourceId sourceId, - QmlDesigner::ModuleId moduleId), + const QmlDesigner::Storage::ProjectData &projectData), (override)); }; From 428a9ee509afd4ac5fdee1395495c6ec3f1ab579 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 20 Oct 2021 17:34:46 +0200 Subject: [PATCH 115/117] QmlDesigner: Use one synchronization struct The arguments of the synchronization function are changing constantly, so all tests have to adapted even for default arguments. To reduce this changes now a struct is used as parameter. Task-number: QDS-5196 Change-Id: Id3b6a530bcb8ab043eccce6526088f345d746235 Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Bot --- .../projectstorage/projectstorage.h | 52 +- .../projectstorage/projectstorageinterface.h | 6 +- .../projectstorage/projectstoragetypes.h | 31 + .../projectstorage/projectstorageupdater.cpp | 61 +- .../projectstorage/projectstorageupdater.h | 20 +- tests/unit/unittest/projectstorage-test.cpp | 2979 ++++++----------- tests/unit/unittest/projectstoragemock.h | 8 +- .../unittest/projectstorageupdater-test.cpp | 126 +- 8 files changed, 1264 insertions(+), 2019 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 2e7b0629cc5..5df23b73854 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -60,10 +60,7 @@ public: moduleCache.populate(); } - void synchronize(Storage::Imports imports, - Storage::Types types, - SourceIds sourceIds, - FileStatuses fileStatuses) override + void synchronize(Storage::SynchronizationPackage package) override { Sqlite::ImmediateTransaction transaction{database}; @@ -76,19 +73,19 @@ public: TypeIds deletedTypeIds; TypeIds updatedTypeIds; - updatedTypeIds.reserve(types.size()); + updatedTypeIds.reserve(package.types.size()); TypeIds typeIdsToBeDeleted; - auto sourceIdValues = Utils::transform(sourceIds, [](SourceId sourceId) { + auto sourceIdValues = Utils::transform(package.sourceIds, [](SourceId sourceId) { return &sourceId; }); std::sort(sourceIdValues.begin(), sourceIdValues.end()); - synchronizeFileStatuses(fileStatuses, sourceIdValues); - synchronizeImports(imports, sourceIdValues); - synchronizeTypes(types, + synchronizeFileStatuses(package.fileStatuses, sourceIdValues); + synchronizeImports(package.imports, sourceIdValues); + synchronizeTypes(package.types, updatedTypeIds, insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations, @@ -897,22 +894,26 @@ private: if (!type.moduleId) throw QmlDesigner::ModuleDoesNotExists{}; - if (type.version) { - insertExportedTypeNamesWithVersionStatement.write(&type.moduleId, - type.name, - type.version.major.value, - type.version.minor.value, - &type.typeId); + try { + if (type.version) { + insertExportedTypeNamesWithVersionStatement.write(&type.moduleId, + type.name, + type.version.major.value, + type.version.minor.value, + &type.typeId); - } else if (type.version.major) { - insertExportedTypeNamesWithMajorVersionStatement.write(&type.moduleId, - type.name, - type.version.major.value, - &type.typeId); - } else { - insertExportedTypeNamesWithoutVersionStatement.write(&type.moduleId, - type.name, - &type.typeId); + } else if (type.version.major) { + insertExportedTypeNamesWithMajorVersionStatement.write(&type.moduleId, + type.name, + type.version.major.value, + &type.typeId); + } else { + insertExportedTypeNamesWithoutVersionStatement.write(&type.moduleId, + type.name, + &type.typeId); + } + } catch (const Sqlite::ConstraintPreventsModification &) { + throw QmlDesigner::ModuleDoesNotExists{}; } }; @@ -1858,8 +1859,7 @@ private: auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", foreignModuleIdColumn, Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::Enforment::Deferred); + Sqlite::ForeignKeyAction::NoAction); auto &nameColumn = table.addColumn("name"); auto &typeIdColumn = table.addColumn("typeId"); auto &majorVersionColumn = table.addColumn("majorVersion"); diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h index 219c6137a10..7d27bd22f1d 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h @@ -33,11 +33,7 @@ namespace QmlDesigner { class ProjectStorageInterface { public: - virtual void synchronize(Storage::Imports imports, - Storage::Types types, - SourceIds sourceIds, - FileStatuses fileStatuses) - = 0; + virtual void synchronize(Storage::SynchronizationPackage package) = 0; virtual ModuleId moduleId(Utils::SmallStringView name) = 0; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index 43a0109a6ad..ef055390767 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -25,6 +25,7 @@ #pragma once +#include "filestatus.h" #include "projectstorageids.h" #include @@ -726,4 +727,34 @@ public: using ProjectDatas = std::vector; +class SynchronizationPackage +{ +public: + SynchronizationPackage() = default; + SynchronizationPackage(Imports imports, Types types, SourceIds sourceIds) + : imports{std::move(imports)} + , types{std::move(types)} + , sourceIds(std::move(sourceIds)) + {} + + SynchronizationPackage(Types types) + : types{std::move(types)} + {} + + SynchronizationPackage(SourceIds sourceIds) + : sourceIds(std::move(sourceIds)) + {} + + SynchronizationPackage(SourceIds sourceIds, FileStatuses fileStatuses) + : sourceIds(std::move(sourceIds)) + , fileStatuses(std::move(fileStatuses)) + {} + +public: + Imports imports; + Types types; + SourceIds sourceIds; + FileStatuses fileStatuses; +}; + } // namespace QmlDesigner::Storage diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp index 83fc1399ab9..cc91a06faee 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp @@ -52,40 +52,34 @@ ComponentReferences createComponentReferences(const QMultiHash &idPaths) {} void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, SourceContextId directoryId, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) + Storage::SynchronizationPackage &package) { QString directory{m_pathCache.sourceContextPath(directoryId)}; @@ -118,44 +106,35 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, Storage::ProjectData projectData{ModuleId{}, sourceId}; - parseTypeInfo(projectData, qmltypesPath, imports, types, sourceIds, fileStatuses); + parseTypeInfo(projectData, qmltypesPath, package); } } void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) + Storage::SynchronizationPackage &package) { for (const Storage::ProjectData &projectData : projectDatas) { QString qmltypesPath = m_pathCache.sourcePath(projectData.sourceId).toQString(); - parseTypeInfo(projectData, qmltypesPath, imports, types, sourceIds, fileStatuses); + parseTypeInfo(projectData, qmltypesPath, package); } } void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData, const QString &qmltypesPath, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) + Storage::SynchronizationPackage &package) { - if (fileState(projectData.sourceId, fileStatuses) == FileState::Changed) { - sourceIds.push_back(projectData.sourceId); + if (fileState(projectData.sourceId, package.fileStatuses) == FileState::Changed) { + package.sourceIds.push_back(projectData.sourceId); const auto content = m_fileSystem.contentAsQString(qmltypesPath); - m_qmlTypesParser.parse(content, imports, types, projectData); + m_qmlTypesParser.parse(content, package.imports, package.types, projectData); } } void ProjectUpdater::parseQmlComponents(ComponentReferences components, SourceContextId directoryId, ModuleId moduleId, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) + Storage::SynchronizationPackage &package) { std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) { return std::tie(first.get().typeName, first.get().majorVersion, first.get().minorVersion) @@ -175,13 +154,13 @@ void ProjectUpdater::parseQmlComponents(ComponentReferences components, Utils::SmallString fileName{component.fileName}; SourceId sourceId = m_pathCache.sourceId(directoryId, fileName); - if (fileState(sourceId, fileStatuses) != FileState::Changed) + if (fileState(sourceId, package.fileStatuses) != FileState::Changed) continue; - sourceIds.push_back(sourceId); + package.sourceIds.push_back(sourceId); const auto content = m_fileSystem.contentAsQString(directory + "/" + component.fileName); - auto type = m_qmlDocumentParser.parse(content, imports); + auto type = m_qmlDocumentParser.parse(content, package.imports); type.typeName = fileName; type.accessSemantics = Storage::TypeAccessSemantics::Reference; @@ -191,7 +170,7 @@ void ProjectUpdater::parseQmlComponents(ComponentReferences components, Utils::SmallString{component.typeName}, Storage::Version{component.majorVersion, component.minorVersion}}); - types.push_back(std::move(type)); + package.types.push_back(std::move(type)); } } diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h index 2ef61aaaf97..e3323d76099 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h @@ -88,28 +88,16 @@ private: void parseTypeInfos(const QStringList &typeInfos, SourceContextId directoryId, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); + Storage::SynchronizationPackage &package); void parseTypeInfos(const Storage::ProjectDatas &projectDatas, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); + Storage::SynchronizationPackage &package); void parseTypeInfo(const Storage::ProjectData &projectData, const QString &qmltypesPath, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); + Storage::SynchronizationPackage &package); void parseQmlComponents(ComponentReferences components, SourceContextId directoryId, ModuleId moduleId, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); + Storage::SynchronizationPackage &package); FileState fileState(SourceId sourceId, FileStatuses &fileStatuses) const; diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp index bd6fda06bc3..43ac728fd99 100644 --- a/tests/unit/unittest/projectstorage-test.cpp +++ b/tests/unit/unittest/projectstorage-test.cpp @@ -46,6 +46,7 @@ using QmlDesigner::SourceIds; using QmlDesigner::TypeId; using QmlDesigner::Cache::Source; using QmlDesigner::Cache::SourceContext; +using QmlDesigner::Storage::SynchronizationPackage; using QmlDesigner::Storage::TypeAccessSemantics; namespace Storage = QmlDesigner::Storage; @@ -202,14 +203,16 @@ protected: storage.fetchSourceId(sourceContextId3, "bar"); } - auto createTypes() + auto createSimpleSynchronizationPackage() { - imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1); - imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1); - imports.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId1); - imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId2); - imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId2); + SynchronizationPackage package; + + package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1); + package.imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1); + package.imports.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId1); + package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId2); + package.imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId2); importsSourceId1.emplace_back(qmlModuleId, Storage::Version{}, sourceId1); importsSourceId1.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1); @@ -219,110 +222,67 @@ protected: importsSourceId2.emplace_back(qmlModuleId, Storage::Version{}, sourceId2); importsSourceId2.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId2); - return Storage::Types{ - Storage::Type{ - "QQuickItem", - Storage::ImportedType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qtQuickModuleId, "Item"}, - Storage::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}, - {Storage::PropertyDeclaration{"data", - Storage::ImportedType{"QObject"}, - Storage::PropertyDeclarationTraits::IsList}, - Storage::PropertyDeclaration{"children", - Storage::ImportedType{"Item"}, - Storage::PropertyDeclarationTraits::IsList - | Storage::PropertyDeclarationTraits::IsReadOnly}}, - {Storage::FunctionDeclaration{"execute", "", {Storage::ParameterDeclaration{"arg", ""}}}, - Storage::FunctionDeclaration{ - "values", - "Vector3D", - {Storage::ParameterDeclaration{"arg1", "int"}, - Storage::ParameterDeclaration{"arg2", - "QObject", - Storage::PropertyDeclarationTraits::IsPointer}, - Storage::ParameterDeclaration{"arg3", "string"}}}}, - {Storage::SignalDeclaration{"execute", {Storage::ParameterDeclaration{"arg", ""}}}, - Storage::SignalDeclaration{ - "value0s", - {Storage::ParameterDeclaration{"arg1", "int"}, - Storage::ParameterDeclaration{"arg2", - "QObject", - Storage::PropertyDeclarationTraits::IsPointer}, - Storage::ParameterDeclaration{"arg3", "string"}}}}, - {Storage::EnumerationDeclaration{"Enum", - {Storage::EnumeratorDeclaration{"Foo"}, - Storage::EnumeratorDeclaration{"Bar", 32}}}, - Storage::EnumerationDeclaration{"Type", - {Storage::EnumeratorDeclaration{"Foo"}, - Storage::EnumeratorDeclaration{"Poo", 12}}}}}, + package.types.push_back(Storage::Type{ + "QQuickItem", + Storage::ImportedType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qtQuickModuleId, "Item"}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}, + {Storage::PropertyDeclaration{"data", + Storage::ImportedType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList}, + Storage::PropertyDeclaration{"children", + Storage::ImportedType{"Item"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly}}, + {Storage::FunctionDeclaration{"execute", "", {Storage::ParameterDeclaration{"arg", ""}}}, + Storage::FunctionDeclaration{ + "values", + "Vector3D", + {Storage::ParameterDeclaration{"arg1", "int"}, + Storage::ParameterDeclaration{"arg2", + "QObject", + Storage::PropertyDeclarationTraits::IsPointer}, + Storage::ParameterDeclaration{"arg3", "string"}}}}, + {Storage::SignalDeclaration{"execute", {Storage::ParameterDeclaration{"arg", ""}}}, + Storage::SignalDeclaration{"value0s", + {Storage::ParameterDeclaration{"arg1", "int"}, + Storage::ParameterDeclaration{ + "arg2", "QObject", Storage::PropertyDeclarationTraits::IsPointer}, + Storage::ParameterDeclaration{"arg3", "string"}}}}, + {Storage::EnumerationDeclaration{"Enum", + {Storage::EnumeratorDeclaration{"Foo"}, + Storage::EnumeratorDeclaration{"Bar", 32}}}, + Storage::EnumerationDeclaration{"Type", + {Storage::EnumeratorDeclaration{"Foo"}, + Storage::EnumeratorDeclaration{"Poo", 12}}}}}); + package.types.push_back( Storage::Type{"QObject", Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId2, {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2}}, Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2}}, - Storage::ExportedType{qmlNativeModuleId, "QObject"}}}}; + Storage::ExportedType{qmlNativeModuleId, "QObject"}}}); + + package.sourceIds = {sourceId1, sourceId2}; + + return package; } - auto createVersionedTypes() + auto createSynchronizationPackageWithAliases() { - return Storage::Types{ - Storage::Type{"QObject", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{1}}, - Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{1, 2}}, - Storage::ExportedType{qmlModuleId, "BuiltInObj"}, - Storage::ExportedType{qmlNativeModuleId, "QObject"}}}, - Storage::Type{"QObject2", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2, 0}}, - Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2, 3}}, - Storage::ExportedType{qmlNativeModuleId, "QObject2"}}}, - Storage::Type{"QObject3", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2, 11}}, - Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2, 11}}, - Storage::ExportedType{qmlNativeModuleId, "QObject3"}}}, - Storage::Type{"QObject4", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{3, 4}}, - Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{3, 4}}, - Storage::ExportedType{qmlModuleId, "BuiltInObj", Storage::Version{3, 4}}, - Storage::ExportedType{qmlNativeModuleId, "QObject4"}}}}; - } + auto package{createSimpleSynchronizationPackage()}; - auto createTypesWithExportedTypeNamesOnly() - { - auto types = createTypes(); + package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3); + package.imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.imports.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId3); - types[0].prototype = Storage::ImportedType{"Object"}; - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object"}; - - return types; - } - - auto createTypesWithAliases() - { - auto types = createTypes(); - - imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3); - imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); - imports.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId3); - - imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4); - imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId4); + package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4); + package.imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId4); importsSourceId3.emplace_back(qmlModuleId, Storage::Version{}, sourceId3); importsSourceId3.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3); @@ -333,75 +293,119 @@ protected: importsSourceId4.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); importsSourceId4.emplace_back(pathToModuleId, Storage::Version{}, sourceId4); - types[1].propertyDeclarations.push_back( + package.types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsList}); - - types.push_back(Storage::Type{"QAliasItem", - Storage::ImportedType{"Item"}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{qtQuickModuleId, "AliasItem"}, - Storage::ExportedType{qtQuickNativeModuleId, "QAliasItem"}}}); - types.back().propertyDeclarations.push_back( + package.types.push_back( + Storage::Type{"QAliasItem", + Storage::ImportedType{"Item"}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{qtQuickModuleId, "AliasItem"}, + Storage::ExportedType{qtQuickNativeModuleId, "QAliasItem"}}}); + package.types.back().propertyDeclarations.push_back( Storage::PropertyDeclaration{"data", Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsList}); - types.back().propertyDeclarations.push_back( + package.types.back().propertyDeclarations.push_back( Storage::PropertyDeclaration{"items", Storage::ImportedType{"Item"}, "children"}); - types.back().propertyDeclarations.push_back( + package.types.back().propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"Item"}, "objects"}); - types.push_back(Storage::Type{"QObject2", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId4, - {Storage::ExportedType{pathToModuleId, "Object2"}, - Storage::ExportedType{pathToModuleId, "Obj2"}}}); - types[3].propertyDeclarations.push_back( + package.types.push_back(Storage::Type{"QObject2", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId4, + {Storage::ExportedType{pathToModuleId, "Object2"}, + Storage::ExportedType{pathToModuleId, "Obj2"}}}); + package.types[3].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsList}); - return types; + package.sourceIds.push_back(sourceId3); + package.sourceIds.push_back(sourceId4); + + return package; } - auto createTypesWithRecursiveAliases() + auto createSynchronizationPackageWithAliases2() { - imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId5); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5); + auto package{createSynchronizationPackageWithAliases()}; - auto types = createTypesWithAliases(); - types.push_back(Storage::Type{"QAliasItem2", - Storage::ImportedType{"Object"}, - TypeAccessSemantics::Reference, - sourceId5, - {Storage::ExportedType{qtQuickModuleId, "AliasItem2"}, - Storage::ExportedType{qtQuickNativeModuleId, "QAliasItem2"}}}); + package.types[2].prototype = Storage::ImportedType{"Object"}; + package.types[2].propertyDeclarations.erase( + std::next(package.types[2].propertyDeclarations.begin())); - types.back().propertyDeclarations.push_back( + return package; + } + + auto createSynchronizationPackageWithRecursiveAliases() + { + auto package{createSynchronizationPackageWithAliases()}; + + package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId5); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5); + + package.types.push_back( + Storage::Type{"QAliasItem2", + Storage::ImportedType{"Object"}, + TypeAccessSemantics::Reference, + sourceId5, + {Storage::ExportedType{qtQuickModuleId, "AliasItem2"}, + Storage::ExportedType{qtQuickNativeModuleId, "QAliasItem2"}}}); + + package.types.back().propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"AliasItem"}, "objects"}); - return types; + package.sourceIds.push_back(sourceId5); + + return package; } - auto createTypesWithAliases2() + auto createSynchronizationPackageWithVersions() { - auto types = createTypesWithAliases(); - types[2].prototype = Storage::ImportedType{"Object"}; - types[2].propertyDeclarations.erase(std::next(types[2].propertyDeclarations.begin())); + SynchronizationPackage package; - return types; - } + package.types.push_back( + Storage::Type{"QObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{1}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{1, 2}}, + Storage::ExportedType{qmlModuleId, "BuiltInObj"}, + Storage::ExportedType{qmlNativeModuleId, "QObject"}}}); + package.types.push_back( + Storage::Type{"QObject2", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2, 0}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2, 3}}, + Storage::ExportedType{qmlNativeModuleId, "QObject2"}}}); + package.types.push_back( + Storage::Type{"QObject3", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2, 11}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2, 11}}, + Storage::ExportedType{qmlNativeModuleId, "QObject3"}}}); + package.types.push_back( + Storage::Type{"QObject4", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{3, 4}}, + Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{3, 4}}, + Storage::ExportedType{qmlModuleId, "BuiltInObj", Storage::Version{3, 4}}, + Storage::ExportedType{qmlNativeModuleId, "QObject4"}}}); - Storage::Imports createImports(SourceId sourceId) - { - return Storage::Imports{Storage::Import{qmlModuleId, Storage::Version{2}, sourceId}, - Storage::Import{qmlNativeModuleId, Storage::Version{}, sourceId}, - Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId}, - Storage::Import{qtQuickNativeModuleId, Storage::Version{}, sourceId}, - Storage::Import{pathToModuleId, Storage::Version{}, sourceId}}; + package.sourceIds.push_back(sourceId1); + + return package; } template @@ -426,28 +430,16 @@ protected: QmlDesigner::SourcePathView path3{"/path3/to"}; QmlDesigner::SourcePathView path4{"/path4/to"}; QmlDesigner::SourcePathView path5{"/path5/to"}; - QmlDesigner::SourcePathView modulePath1{"/module/path1/to"}; - QmlDesigner::SourcePathView modulePath2{"/module/path2/to"}; - QmlDesigner::SourcePathView modulePath3{"/module/aaaa/to"}; - QmlDesigner::SourcePathView modulePath4{"/module/ooo/to"}; - QmlDesigner::SourcePathView modulePath5{"/module/xxx/to"}; SourceId sourceId1{sourcePathCache.sourceId(path1)}; SourceId sourceId2{sourcePathCache.sourceId(path2)}; SourceId sourceId3{sourcePathCache.sourceId(path3)}; SourceId sourceId4{sourcePathCache.sourceId(path4)}; SourceId sourceId5{sourcePathCache.sourceId(path5)}; - SourceIds sourceIds{sourceId1, sourceId2, sourceId3, sourceId4, sourceId5}; - SourceId qmlModuleSourceId{sourcePathCache.sourceId(modulePath1)}; - SourceId qtQuickModuleSourceId{sourcePathCache.sourceId(modulePath2)}; - SourceId pathToModuleSourceId{sourcePathCache.sourceId(modulePath3)}; - SourceId moduleSourceId4{sourcePathCache.sourceId(modulePath4)}; - SourceId moduleSourceId5{sourcePathCache.sourceId(modulePath5)}; ModuleId qmlModuleId{storage.moduleId("Qml")}; ModuleId qmlNativeModuleId{storage.moduleId("Qml-cppnative")}; ModuleId qtQuickModuleId{storage.moduleId("QtQuick")}; ModuleId qtQuickNativeModuleId{storage.moduleId("QtQuick-cppnative")}; ModuleId pathToModuleId{storage.moduleId("/path/to")}; - Storage::Imports imports; Storage::Imports importsSourceId1; Storage::Imports importsSourceId2; Storage::Imports importsSourceId3; @@ -659,13 +651,9 @@ TEST_F(ProjectStorage, FetchSourceIdUnguardedWithNonExistingSourceContextIdThrow TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypes) { - Storage::Types types{createTypes()}; + auto package{createSimpleSynchronizationPackage()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(std::move(package)); ASSERT_THAT( storage.fetchTypes(), @@ -686,14 +674,10 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypes) TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExportedPrototypeName) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::ImportedType{"Object"}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::ImportedType{"Object"}; - storage.synchronize( - importsSourceId1, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(std::move(package)); ASSERT_THAT( storage.fetchTypes(), @@ -714,50 +698,31 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExportedPrototypeName) TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesThrowsWithWrongPrototypeName) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::ImportedType{"Objec"}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::ImportedType{"Objec"}; - ASSERT_THROW(storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(std::move(package)), QmlDesigner::TypeNameDoesNotExists); } -TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithMissingModuleAndPrototypeName) +TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithMissingModule) { - Storage::Types types{createTypes()}; - types.push_back(Storage::Type{"QObject2", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{ModuleId{22}, "Object2"}, - Storage::ExportedType{pathToModuleId, "Obj2"}}}); - storage.synchronize( - imports, - {}, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].prototype = Storage::ImportedType{"Object2"}; + auto package{createSimpleSynchronizationPackage()}; + package.types.push_back(Storage::Type{"QObject2", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{ModuleId{22}, "Object2"}, + Storage::ExportedType{pathToModuleId, "Obj2"}}}); - ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(std::move(package)), QmlDesigner::ModuleDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesReverseOrder) { - Storage::Types types{createTypes()}; - std::reverse(types.begin(), types.end()); + auto package{createSimpleSynchronizationPackage()}; + std::reverse(package.types.begin(), package.types.end()); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(std::move(package)); ASSERT_THAT( storage.fetchTypes(), @@ -778,16 +743,12 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesReverseOrder) TEST_F(ProjectStorage, SynchronizeTypesOverwritesTypeAccessSemantics) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].accessSemantics = TypeAccessSemantics::Value; - types[1].accessSemantics = TypeAccessSemantics::Value; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].accessSemantics = TypeAccessSemantics::Value; + package.types[1].accessSemantics = TypeAccessSemantics::Value; - storage.synchronize(imports, types, {sourceId1, sourceId2}, {}); + storage.synchronize(SynchronizationPackage{package.imports, package.types, {sourceId1, sourceId2}}); ASSERT_THAT(storage.fetchTypes(), UnorderedElementsAre( @@ -808,14 +769,10 @@ TEST_F(ProjectStorage, SynchronizeTypesOverwritesTypeAccessSemantics) TEST_F(ProjectStorage, SynchronizeTypesOverwritesSources) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].sourceId = sourceId3; - types[1].sourceId = sourceId4; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].sourceId = sourceId3; + package.types[1].sourceId = sourceId4; Storage::Imports newImports; newImports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3); newImports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3); @@ -824,7 +781,9 @@ TEST_F(ProjectStorage, SynchronizeTypesOverwritesSources) newImports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4); newImports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); - storage.synchronize(newImports, types, {sourceId1, sourceId2, sourceId3, sourceId4}, {}); + storage.synchronize(SynchronizationPackage{newImports, + package.types, + {sourceId1, sourceId2, sourceId3, sourceId4}}); ASSERT_THAT( storage.fetchTypes(), @@ -845,21 +804,19 @@ TEST_F(ProjectStorage, SynchronizeTypesOverwritesSources) TEST_F(ProjectStorage, SynchronizeTypesInsertTypeIntoPrototypeChain) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].prototype = Storage::ImportedType{"QQuickObject"}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qtQuickModuleId, "Object"}, - Storage::ExportedType{qtQuickNativeModuleId, "QQuickObject"}}}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].prototype = Storage::ImportedType{"QQuickObject"}; + package.types.push_back( + Storage::Type{"QQuickObject", + Storage::ImportedType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qtQuickModuleId, "Object"}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickObject"}}}); - storage.synchronize(importsSourceId1, {types[0], types[2]}, {sourceId1}, {}); + storage.synchronize( + SynchronizationPackage{importsSourceId1, {package.types[0], package.types[2]}, {sourceId1}}); ASSERT_THAT( storage.fetchTypes(), @@ -887,23 +844,20 @@ TEST_F(ProjectStorage, SynchronizeTypesInsertTypeIntoPrototypeChain) TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedPrototype) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qtQuickModuleId, - Storage::Version{}, - sourceId1}}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qtQuickModuleId, "Object"}, - Storage::ExportedType{qtQuickNativeModuleId, "QQuickObject"}}}); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qtQuickModuleId, + Storage::Version{}, + sourceId1}}; + package.types.push_back( + Storage::Type{"QQuickObject", + Storage::ImportedType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qtQuickModuleId, "Object"}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickObject"}}}); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT( storage.fetchTypes(), @@ -931,62 +885,48 @@ TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedPrototype) TEST_F(ProjectStorage, SynchronizeTypesThrowsForMissingPrototype) { - sourceId1 = sourcePathCache.sourceId(path1); - Storage::Types types{Storage::Type{"QQuickItem", - Storage::ImportedType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qtQuickModuleId, "Item"}, - Storage::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}}}; + auto package{createSimpleSynchronizationPackage()}; + package.types = {Storage::Type{"QQuickItem", + Storage::ImportedType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qtQuickModuleId, "Item"}, + Storage::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}}}; - ASSERT_THROW(storage.synchronize( - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesThrowsForInvalidModule) { - sourceId1 = sourcePathCache.sourceId(path1); - Storage::Types types{Storage::Type{"QQuickItem", - Storage::ImportedType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{ModuleId{}, "Item"}}}}; + auto package{createSimpleSynchronizationPackage()}; + package.types = {Storage::Type{"QQuickItem", + Storage::ImportedType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{ModuleId{}, "Item"}}}}; - ASSERT_THROW(storage.synchronize(imports, types, {sourceId1}, {}), - QmlDesigner::ModuleDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::ModuleDoesNotExists); } TEST_F(ProjectStorage, TypeWithInvalidSourceIdThrows) { - Storage::Types types{Storage::Type{"QQuickItem", - Storage::ImportedType{""}, - TypeAccessSemantics::Reference, - SourceId{}, - {Storage::ExportedType{qtQuickModuleId, "Item"}}}}; + auto package{createSimpleSynchronizationPackage()}; + package.types = {Storage::Type{"QQuickItem", + Storage::ImportedType{""}, + TypeAccessSemantics::Reference, + SourceId{}, + {Storage::ExportedType{qtQuickModuleId, "Item"}}}}; - ASSERT_THROW(storage.synchronize( - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}), - QmlDesigner::TypeHasInvalidSourceId); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeHasInvalidSourceId); } TEST_F(ProjectStorage, DeleteTypeIfSourceIdIsSynchronized) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types.erase(types.begin()); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types.erase(package.types.begin()); - storage.synchronize(importsSourceId2, types, {sourceId1, sourceId2}, {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), UnorderedElementsAre( @@ -999,15 +939,10 @@ TEST_F(ProjectStorage, DeleteTypeIfSourceIdIsSynchronized) TEST_F(ProjectStorage, DontDeleteTypeIfSourceIdIsNotSynchronized) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); - storage.synchronize(importsSourceId1, types, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT( storage.fetchTypes(), @@ -1028,15 +963,11 @@ TEST_F(ProjectStorage, DontDeleteTypeIfSourceIdIsNotSynchronized) TEST_F(ProjectStorage, UpdateExportedTypesIfTypeNameChanges) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].typeName = "QQuickItem2"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].typeName = "QQuickItem2"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT( storage.fetchTypes(), @@ -1057,27 +988,20 @@ TEST_F(ProjectStorage, UpdateExportedTypesIfTypeNameChanges) TEST_F(ProjectStorage, BreakingPrototypeChainByDeletingBaseComponentThrows) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); - ASSERT_THROW(storage.synchronize(importsSourceId1, types, {sourceId1, sourceId2}, {}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId1, + {package.types[0]}, + {sourceId1, sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarations) { - Storage::Types types{createTypes()}; + auto package{createSimpleSynchronizationPackage()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains( @@ -1097,52 +1021,26 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarations) | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } -TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationsWithMissingImportsForNativeTypes) +TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationsWithMissingImports) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + package.imports.clear(); - ASSERT_THROW(storage.synchronize({}, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); -} - -TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationsWithMissingImportsForExportedTypes) -{ - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Obj"}; - - ASSERT_THROW(storage.synchronize({}, {types[0]}, {sourceId1}, {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationQualifiedType) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + package.types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1, + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains( @@ -1164,15 +1062,12 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationQualifiedType) TEST_F(ProjectStorage, SynchronizeTypesChangesPropertyDeclarationType) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QQuickItem"}; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QQuickItem"}; + + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); ASSERT_THAT(storage.fetchTypes(), Contains( AllOf(IsStorageType(sourceId1, @@ -1193,15 +1088,11 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesPropertyDeclarationType) TEST_F(ProjectStorage, SynchronizeTypesChangesDeclarationTraits) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), Contains( @@ -1223,16 +1114,12 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesDeclarationTraits) TEST_F(ProjectStorage, SynchronizeTypesChangesDeclarationTraitsAndType) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer; - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QQuickItem"}; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer; + package.types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QQuickItem"}; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), Contains( @@ -1254,15 +1141,11 @@ TEST_F(ProjectStorage, SynchronizeTypesChangesDeclarationTraitsAndType) TEST_F(ProjectStorage, SynchronizeTypesRemovesAPropertyDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].propertyDeclarations.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].propertyDeclarations.pop_back(); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf(IsStorageType(sourceId1, @@ -1278,18 +1161,14 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovesAPropertyDeclaration) TEST_F(ProjectStorage, SynchronizeTypesAddsAPropertyDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].propertyDeclarations.push_back( + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"object", Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsPointer}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT( storage.fetchTypes(), @@ -1314,15 +1193,11 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsAPropertyDeclaration) TEST_F(ProjectStorage, SynchronizeTypesRenameAPropertyDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].propertyDeclarations[1].name = "objects"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].propertyDeclarations[1].name = "objects"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), Contains( @@ -1342,703 +1217,572 @@ TEST_F(ProjectStorage, SynchronizeTypesRenameAPropertyDeclaration) | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } -TEST_F(ProjectStorage, UsingNonExistingNativePropertyTypeThrows) +TEST_F(ProjectStorage, UsingNonExistingPropertyTypeThrows) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QObject2"}; - types.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QObject2"}; + package.types.pop_back(); + package.imports = importsSourceId1; - ASSERT_THROW(storage.synchronize(importsSourceId1, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); -} - -TEST_F(ProjectStorage, UsingNonExistingExportedPropertyTypeThrows) -{ - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"QObject2"}; - types.pop_back(); - - ASSERT_THROW(storage.synchronize(importsSourceId1, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, UsingNonExistingQualifiedExportedPropertyTypeWithWrongNameThrows) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "QObject2", Storage::Import{qmlNativeModuleId, Storage::Version{}, sourceId1}}; - types.pop_back(); + package.types.pop_back(); + package.imports = importsSourceId1; - ASSERT_THROW(storage.synchronize(importsSourceId1, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, UsingNonExistingQualifiedExportedPropertyTypeWithWrongModuleThrows) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "QObject", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; - types.pop_back(); + package.types.pop_back(); + package.imports = importsSourceId1; - ASSERT_THROW(storage.synchronize(importsSourceId1, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, BreakingPropertyDeclarationTypeDependencyByDeletingTypeThrows) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].prototype = Storage::ImportedType{}; - types.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].prototype = Storage::ImportedType{}; + package.types.pop_back(); + package.imports = importsSourceId1; - ASSERT_THROW(storage.synchronize(importsSourceId1, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesAddFunctionDeclarations) { - Storage::Types types{createTypes()}; + auto package{createSimpleSynchronizationPackage()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationReturnType) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations[1].returnTypeName = "item"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations[1].returnTypeName = "item"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations[1].name = "name"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations[1].name = "name"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationPopParameters) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations[1].parameters.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations[1].parameters.pop_back(); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationAppendParameters) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations[1].parameters.push_back(Storage::ParameterDeclaration{"arg4", "int"}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations[1].parameters.push_back( + Storage::ParameterDeclaration{"arg4", "int"}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationChangeParameterName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations[1].parameters[0].name = "other"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations[1].parameters[0].name = "other"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationChangeParameterTypeName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations[1].parameters[0].name = "long long"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations[1].parameters[0].name = "long long"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesFunctionDeclarationChangeParameterTraits) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations[1].parameters[0].traits = QmlDesigner::Storage:: + PropertyDeclarationTraits::IsList; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesRemovesFunctionDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations.pop_back(); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0])))))); } TEST_F(ProjectStorage, SynchronizeTypesAddFunctionDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].functionDeclarations.push_back( + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].functionDeclarations.push_back( Storage::FunctionDeclaration{"name", "string", {Storage::ParameterDeclaration{"arg", "int"}}}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::functionDeclarations, - UnorderedElementsAre(Eq(types[0].functionDeclarations[0]), - Eq(types[0].functionDeclarations[1]), - Eq(types[0].functionDeclarations[2])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(Eq(package.types[0].functionDeclarations[0]), + Eq(package.types[0].functionDeclarations[1]), + Eq(package.types[0].functionDeclarations[2])))))); } TEST_F(ProjectStorage, SynchronizeTypesAddSignalDeclarations) { - Storage::Types types{createTypes()}; + auto package{createSimpleSynchronizationPackage()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), - Eq(types[0].signalDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0]), + Eq(package.types[0].signalDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].signalDeclarations[1].name = "name"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].signalDeclarations[1].name = "name"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), - Eq(types[0].signalDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0]), + Eq(package.types[0].signalDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationPopParameters) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].signalDeclarations[1].parameters.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].signalDeclarations[1].parameters.pop_back(); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), - Eq(types[0].signalDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0]), + Eq(package.types[0].signalDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationAppendParameters) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].signalDeclarations[1].parameters.push_back(Storage::ParameterDeclaration{"arg4", "int"}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].signalDeclarations[1].parameters.push_back( + Storage::ParameterDeclaration{"arg4", "int"}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), - Eq(types[0].signalDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0]), + Eq(package.types[0].signalDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationChangeParameterName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].signalDeclarations[1].parameters[0].name = "other"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].signalDeclarations[1].parameters[0].name = "other"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), - Eq(types[0].signalDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0]), + Eq(package.types[0].signalDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationChangeParameterTypeName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].signalDeclarations[1].parameters[0].typeName = "long long"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].signalDeclarations[1].parameters[0].typeName = "long long"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), - Eq(types[0].signalDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0]), + Eq(package.types[0].signalDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesSignalDeclarationChangeParameterTraits) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].signalDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].signalDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), - Eq(types[0].signalDeclarations[1])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0]), + Eq(package.types[0].signalDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesRemovesSignalDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].signalDeclarations.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].signalDeclarations.pop_back(); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0])))))); } TEST_F(ProjectStorage, SynchronizeTypesAddSignalDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].signalDeclarations.push_back( + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].signalDeclarations.push_back( Storage::SignalDeclaration{"name", {Storage::ParameterDeclaration{"arg", "int"}}}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::signalDeclarations, - UnorderedElementsAre(Eq(types[0].signalDeclarations[0]), - Eq(types[0].signalDeclarations[1]), - Eq(types[0].signalDeclarations[2])))))); + Contains( + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(Eq(package.types[0].signalDeclarations[0]), + Eq(package.types[0].signalDeclarations[1]), + Eq(package.types[0].signalDeclarations[2])))))); } TEST_F(ProjectStorage, SynchronizeTypesAddEnumerationDeclarations) { - Storage::Types types{createTypes()}; + auto package{createSimpleSynchronizationPackage()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations[1].name = "Name"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations[1].name = "Name"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationPopEnumeratorDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations[1].enumeratorDeclarations.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations[1].enumeratorDeclarations.pop_back(); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationAppendEnumeratorDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations[1].enumeratorDeclarations.push_back( + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations[1].enumeratorDeclarations.push_back( Storage::EnumeratorDeclaration{"Haa", 54}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationChangeEnumeratorDeclarationName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations[1].enumeratorDeclarations[0].name = "Hoo"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations[1].enumeratorDeclarations[0].name = "Hoo"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationChangeEnumeratorDeclarationValue) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations[1].enumeratorDeclarations[1].value = 11; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations[1].enumeratorDeclarations[1].value = 11; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationAddThatEnumeratorDeclarationHasValue) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations[1].enumeratorDeclarations[0].value = 11; - types[0].enumerationDeclarations[1].enumeratorDeclarations[0].hasValue = true; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations[1].enumeratorDeclarations[0].value = 11; + package.types[0].enumerationDeclarations[1].enumeratorDeclarations[0].hasValue = true; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesChangesEnumerationDeclarationRemoveThatEnumeratorDeclarationHasValue) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations[1].enumeratorDeclarations[0].hasValue = false; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations[1].enumeratorDeclarations[0].hasValue = false; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1])))))); } TEST_F(ProjectStorage, SynchronizeTypesRemovesEnumerationDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations.pop_back(); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf(IsStorageType(sourceId1, @@ -2046,41 +1790,35 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovesEnumerationDeclaration) fetchTypeId(sourceId2, "QObject"), TypeAccessSemantics::Reference), Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0])))))); + UnorderedElementsAre( + Eq(package.types[0].enumerationDeclarations[0])))))); } TEST_F(ProjectStorage, SynchronizeTypesAddEnumerationDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].enumerationDeclarations.push_back( + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].enumerationDeclarations.push_back( Storage::EnumerationDeclaration{"name", {Storage::EnumeratorDeclaration{"Foo", 98, true}}}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(sourceId1, - "QQuickItem", - fetchTypeId(sourceId2, "QObject"), - TypeAccessSemantics::Reference), - Field(&Storage::Type::enumerationDeclarations, - UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]), - Eq(types[0].enumerationDeclarations[1]), - Eq(types[0].enumerationDeclarations[2])))))); + Contains(AllOf( + IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::enumerationDeclarations, + UnorderedElementsAre(Eq(package.types[0].enumerationDeclarations[0]), + Eq(package.types[0].enumerationDeclarations[1]), + Eq(package.types[0].enumerationDeclarations[2])))))); } TEST_F(ProjectStorage, FetchTypeIdBySourceIdAndName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); auto typeId = storage.fetchTypeIdByName(sourceId2, "QObject"); @@ -2089,12 +1827,8 @@ TEST_F(ProjectStorage, FetchTypeIdBySourceIdAndName) TEST_F(ProjectStorage, FetchTypeIdByExportedName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); auto typeId = storage.fetchTypeIdByExportedName("Object"); @@ -2103,12 +1837,8 @@ TEST_F(ProjectStorage, FetchTypeIdByExportedName) TEST_F(ProjectStorage, FetchTypeIdByImporIdsAndExportedName) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({qmlModuleId, qtQuickModuleId}, "Object"); @@ -2118,12 +1848,8 @@ TEST_F(ProjectStorage, FetchTypeIdByImporIdsAndExportedName) TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAreEmpty) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({}, "Object"); @@ -2132,12 +1858,8 @@ TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAre TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAreInvalid) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({ModuleId{}}, "Object"); @@ -2146,12 +1868,8 @@ TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAre TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfNotInModule) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); auto qtQuickModuleId = storage.moduleId("QtQuick"); auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({qtQuickModuleId}, "Object"); @@ -2161,18 +1879,9 @@ TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfNotInModule) TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarations) { - Storage::Types types{createTypesWithAliases()}; + auto package{createSynchronizationPackageWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2196,28 +1905,10 @@ TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarations) TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsAgain) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2241,20 +1932,11 @@ TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsAgain) TEST_F(ProjectStorage, SynchronizeTypesRemoveAliasDeclarations) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[2].propertyDeclarations.pop_back(); + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations.pop_back(); - storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId3, {package.types[2]}, {sourceId3}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2275,38 +1957,31 @@ TEST_F(ProjectStorage, SynchronizeTypesRemoveAliasDeclarations) TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsThrowsForWrongTypeName) { - Storage::Types types{createTypesWithAliases()}; - types[2].propertyDeclarations[1].typeName = Storage::ImportedType{"QQuickItemWrong"}; + auto package{createSynchronizationPackageWithAliases()}; + package.types[2].propertyDeclarations[1].typeName = Storage::ImportedType{"QQuickItemWrong"}; - ASSERT_THROW(storage.synchronize(importsSourceId4, {types[2]}, {sourceId4}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId4, {package.types[2]}, {sourceId4}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarationsThrowsForWrongPropertyName) { - Storage::Types types{createTypesWithAliases()}; - types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; + auto package{createSynchronizationPackageWithAliases()}; + package.types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; - ASSERT_THROW(storage.synchronize(imports, types, {sourceId4}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{package.imports, package.types, {sourceId4}}), QmlDesigner::PropertyNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsTypeName) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Obj2"}; + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Obj2"}; importsSourceId3.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); - storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId3, {package.types[2]}, {sourceId3}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2330,20 +2005,11 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsTypeName) TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsPropertyName) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[2].propertyDeclarations[2].aliasPropertyName = "children"; + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations[2].aliasPropertyName = "children"; - storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId3, {package.types[2]}, {sourceId3}}); ASSERT_THAT( storage.fetchTypes(), @@ -2369,25 +2035,16 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsPropertyName) TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsToPropertyDeclaration) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[2].propertyDeclarations.pop_back(); - types[2].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations.pop_back(); + package.types[2].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId3, {package.types[2]}, {sourceId3}}); ASSERT_THAT( storage.fetchTypes(), @@ -2413,26 +2070,17 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsToPropertyDeclarat TEST_F(ProjectStorage, SynchronizeTypesChangePropertyDeclarationsToAliasDeclaration) { - Storage::Types types{createTypesWithAliases()}; - auto typesChanged = types; - typesChanged[2].propertyDeclarations.pop_back(); - typesChanged[2].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithAliases()}; + auto packageChanged = package; + packageChanged.types[2].propertyDeclarations.pop_back(); + packageChanged.types[2].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(imports, - typesChanged, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(packageChanged); - storage.synchronize(imports, types, {sourceId1, sourceId2, sourceId3, sourceId4}, {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2456,21 +2104,12 @@ TEST_F(ProjectStorage, SynchronizeTypesChangePropertyDeclarationsToAliasDeclarat TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTraits) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList - | Storage::PropertyDeclarationTraits::IsReadOnly; + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[1].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly; - storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); ASSERT_THAT( storage.fetchTypes(), @@ -2496,21 +2135,12 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTrait TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTypeName) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Item"}; + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Item"}; importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2534,43 +2164,25 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTypeN TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationWithAnAliasThrows) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations.pop_back(); + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[1].propertyDeclarations.pop_back(); - ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), Sqlite::ConstraintPreventsModification); } TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationAndAlias) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations.pop_back(); - types[2].propertyDeclarations.pop_back(); + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[1].propertyDeclarations.pop_back(); + package.types[2].propertyDeclarations.pop_back(); - storage.synchronize(importsSourceId2 + importsSourceId3, - {types[1], types[2]}, - {sourceId2, sourceId3}, - {}); + storage.synchronize(SynchronizationPackage{importsSourceId2 + importsSourceId3, + {package.types[1], package.types[2]}, + {sourceId2, sourceId3}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2591,44 +2203,26 @@ TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationAndAlias) TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeWithAliasTargetPropertyDeclarationThrows) { - Storage::Types types{createTypesWithAliases()}; - types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithAliases()}; + package.types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Object2"}; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); + storage.synchronize(package); - ASSERT_THROW(storage.synchronize({}, {}, {sourceId4}, {}), QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{sourceId4}}), + QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeAndAliasPropertyDeclaration) { - Storage::Types types{createTypesWithAliases()}; - types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[2].propertyDeclarations.pop_back(); + auto package{createSynchronizationPackageWithAliases()}; + package.types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Object2"}; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); + storage.synchronize(package); + package.types[2].propertyDeclarations.pop_back(); - storage.synchronize(importsSourceId1 + importsSourceId3, - {types[0], types[2]}, - {sourceId1, sourceId3}, - {}); + storage.synchronize(SynchronizationPackage{importsSourceId1 + importsSourceId3, + {package.types[0], package.types[2]}, + {sourceId1, sourceId3}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2649,24 +2243,15 @@ TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeAndAliasPropertyDeclaration) TEST_F(ProjectStorage, UpdateAliasPropertyIfPropertyIsOverloaded) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[0].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT( storage.fetchTypes(), @@ -2692,23 +2277,14 @@ TEST_F(ProjectStorage, UpdateAliasPropertyIfPropertyIsOverloaded) TEST_F(ProjectStorage, AliasPropertyIsOverloaded) { - Storage::Types types{createTypesWithAliases()}; - types[0].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithAliases()}; + package.types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT( storage.fetchTypes(), @@ -2734,25 +2310,16 @@ TEST_F(ProjectStorage, AliasPropertyIsOverloaded) TEST_F(ProjectStorage, UpdateAliasPropertyIfOverloadedPropertyIsRemoved) { - Storage::Types types{createTypesWithAliases()}; - types[0].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithAliases()}; + package.types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[0].propertyDeclarations.pop_back(); + storage.synchronize(package); + package.types[0].propertyDeclarations.pop_back(); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2776,23 +2343,14 @@ TEST_F(ProjectStorage, UpdateAliasPropertyIfOverloadedPropertyIsRemoved) TEST_F(ProjectStorage, RelinkAliasProperty) { - Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].exportedTypes[0].moduleId = qtQuickModuleId; + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + storage.synchronize(package); + package.types[3].exportedTypes[0].moduleId = qtQuickModuleId; - storage.synchronize(importsSourceId4, {types[3]}, {sourceId4}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId4, {package.types[3]}, {sourceId4}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2816,52 +2374,35 @@ TEST_F(ProjectStorage, RelinkAliasProperty) TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForQualifiedImportedTypeName) { - Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object2", Storage::Import{pathToModuleId, Storage::Version{}, sourceId2}}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].exportedTypes[0].moduleId = qtQuickModuleId; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + storage.synchronize(package); + package.types[3].exportedTypes[0].moduleId = qtQuickModuleId; importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4); - ASSERT_THROW(storage.synchronize(importsSourceId4, {types[3]}, {sourceId4}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId4, {package.types[3]}, {sourceId4}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, DoRelinkAliasPropertyForQualifiedImportedTypeNameEvenIfAnOtherSimilarTimeNameExists) { - Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object2", Storage::Import{pathToModuleId, Storage::Version{}, sourceId2}}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - types.push_back(Storage::Type{"QObject2", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId5, - {Storage::ExportedType{qtQuickModuleId, "Object2"}, - Storage::ExportedType{qtQuickModuleId, "Obj2"}}}); + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + package.types.push_back(Storage::Type{"QObject2", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId5, + {Storage::ExportedType{qtQuickModuleId, "Object2"}, + Storage::ExportedType{qtQuickModuleId, "Obj2"}}}); + package.sourceIds.push_back(sourceId5); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2885,22 +2426,13 @@ TEST_F(ProjectStorage, TEST_F(ProjectStorage, RelinkAliasPropertyReactToTypeNameChange) { - Storage::Types types{createTypesWithAliases2()}; - types[2].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithAliases2()}; + package.types[2].propertyDeclarations.push_back( Storage::PropertyDeclaration{"items", Storage::ImportedType{"Item"}, "children"}); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[0].typeName = "QQuickItem2"; + storage.synchronize(package); + package.types[0].typeName = "QQuickItem2"; - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf( @@ -2924,23 +2456,15 @@ TEST_F(ProjectStorage, RelinkAliasPropertyReactToTypeNameChange) TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedType) { - Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].exportedTypes[0].moduleId = qtQuickModuleId; + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + storage.synchronize(package); + package.types[3].exportedTypes[0].moduleId = qtQuickModuleId; - storage.synchronize(importsSourceId4, {types[3]}, {sourceId3, sourceId4}, {}); + storage.synchronize( + SynchronizationPackage{importsSourceId4, {package.types[3]}, {sourceId3, sourceId4}}); ASSERT_THAT(storage.fetchTypes(), Not(Contains(IsStorageType(sourceId3, @@ -2951,57 +2475,37 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedType) TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyType) { - Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[0].prototype = Storage::ImportedType{}; + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + storage.synchronize(package); + package.types[0].prototype = Storage::ImportedType{}; importsSourceId1.emplace_back(pathToModuleId, Storage::Version{}, sourceId1); importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4); - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - types[3].propertyDeclarations[0].typeName = Storage::ImportedType{"Item"}; + package.types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + package.types[3].propertyDeclarations[0].typeName = Storage::ImportedType{"Item"}; - storage.synchronize(importsSourceId1 + importsSourceId4, - {types[0], types[3]}, - {sourceId1, sourceId2, sourceId3, sourceId4}, - {}); + storage.synchronize(SynchronizationPackage{importsSourceId1 + importsSourceId4, + {package.types[0], package.types[3]}, + {sourceId1, sourceId2, sourceId3, sourceId4}}); ASSERT_THAT(storage.fetchTypes(), SizeIs(2)); } TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyTypeNameChange) { - Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].exportedTypes[0].moduleId = qtQuickModuleId; - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"QObject"}; + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + storage.synchronize(package); + package.types[3].exportedTypes[0].moduleId = qtQuickModuleId; + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"QObject"}; importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4); - storage.synchronize(importsSourceId2 + importsSourceId4, - {types[1], types[3]}, - {sourceId2, sourceId3, sourceId4}, - {}); + storage.synchronize(SynchronizationPackage{importsSourceId2 + importsSourceId4, + {package.types[1], package.types[3]}, + {sourceId2, sourceId3, sourceId4}}); ASSERT_THAT(storage.fetchTypes(), Not(Contains(IsStorageType(sourceId3, @@ -3012,54 +2516,34 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyTypeName TEST_F(ProjectStorage, DoNotRelinkPropertyTypeDoesNotExists) { - Storage::Types types{createTypesWithAliases()}; - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + storage.synchronize(package); - ASSERT_THROW(storage.synchronize({}, {}, {sourceId4}, {}), QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{sourceId4}}), + QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, DoNotRelinkAliasPropertyTypeDoesNotExists) { - Storage::Types types{createTypesWithAliases2()}; - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithAliases2()}; + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + storage.synchronize(package); - ASSERT_THROW(storage.synchronize({}, {}, {sourceId1}, {}), QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{sourceId1}}), + QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, ChangePrototypeTypeName) { - Storage::Types types{createTypesWithExportedTypeNamesOnly()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].typeName = "QObject3"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[1].typeName = "QObject3"; - storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId1, @@ -3070,15 +2554,11 @@ TEST_F(ProjectStorage, ChangePrototypeTypeName) TEST_F(ProjectStorage, ChangePrototypeTypeModuleId) { - Storage::Types types{createTypes()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].exportedTypes[2].moduleId = qtQuickModuleId; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[1].exportedTypes[2].moduleId = qtQuickModuleId; - storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId1, @@ -3089,44 +2569,36 @@ TEST_F(ProjectStorage, ChangePrototypeTypeModuleId) TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleIdThrows) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qmlModuleId, - Storage::Version{}, - sourceId1}}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].exportedTypes[0].moduleId = qtQuickModuleId; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qmlModuleId, + Storage::Version{}, + sourceId1}}; + storage.synchronize(package); + package.types[1].exportedTypes[0].moduleId = qtQuickModuleId; - ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleId) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qmlModuleId, - Storage::Version{}, - sourceId1}}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].exportedTypes[0].moduleId = qtQuickModuleId; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qtQuickModuleId, - Storage::Version{}, - sourceId1}}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qmlModuleId, + Storage::Version{}, + sourceId1}}; + storage.synchronize(package); + package.types[1].exportedTypes[0].moduleId = qtQuickModuleId; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qtQuickModuleId, + Storage::Version{}, + sourceId1}}; - storage.synchronize(importsSourceId1 + importsSourceId2, - {types[0], types[1]}, - {sourceId1, sourceId2}, - {}); + storage.synchronize(SynchronizationPackage{importsSourceId1 + importsSourceId2, + {package.types[0], package.types[1]}, + {sourceId1, sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId1, @@ -3137,19 +2609,17 @@ TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleId) TEST_F(ProjectStorage, ChangePrototypeTypeNameAndModuleId) { - Storage::Types types{createTypesWithExportedTypeNamesOnly()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].exportedTypes[0].moduleId = qtQuickModuleId; - types[1].exportedTypes[1].moduleId = qtQuickModuleId; - types[1].exportedTypes[2].moduleId = qtQuickModuleId; - types[1].exportedTypes[2].name = "QObject3"; - types[1].typeName = "QObject3"; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::ImportedType{"Object"}; + package.types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object"}; + storage.synchronize(package); + package.types[1].exportedTypes[0].moduleId = qtQuickModuleId; + package.types[1].exportedTypes[1].moduleId = qtQuickModuleId; + package.types[1].exportedTypes[2].moduleId = qtQuickModuleId; + package.types[1].exportedTypes[2].name = "QObject3"; + package.types[1].typeName = "QObject3"; - storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId1, @@ -3160,93 +2630,63 @@ TEST_F(ProjectStorage, ChangePrototypeTypeNameAndModuleId) TEST_F(ProjectStorage, ChangePrototypeTypeNameThrowsForWrongNativePrototupeTypeName) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object"}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].exportedTypes[2].name = "QObject3"; - types[1].typeName = "QObject3"; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object"}; + storage.synchronize(package); + package.types[1].exportedTypes[2].name = "QObject3"; + package.types[1].typeName = "QObject3"; - ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, ThrowForPrototypeChainCycles) { - Storage::Types types{createTypes()}; - types[1].prototype = Storage::ImportedType{"Object2"}; - types.push_back(Storage::Type{"QObject2", - Storage::ImportedType{"Item"}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{pathToModuleId, "Object2"}, - Storage::ExportedType{pathToModuleId, "Obj2"}}}); - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); - imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); + auto package{createSimpleSynchronizationPackage()}; + package.types[1].prototype = Storage::ImportedType{"Object2"}; + package.types.push_back(Storage::Type{"QObject2", + Storage::ImportedType{"Item"}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{pathToModuleId, "Object2"}, + Storage::ExportedType{pathToModuleId, "Obj2"}}}); + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3); - ASSERT_THROW(storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{package.imports, + package.types, + {sourceId1, sourceId2, sourceId3}}), QmlDesigner::PrototypeChainCycle); } TEST_F(ProjectStorage, ThrowForTypeIdAndPrototypeIdAreTheSame) { - Storage::Types types{createTypes()}; - types[1].prototype = Storage::ImportedType{"Object"}; + auto package{createSimpleSynchronizationPackage()}; + package.types[1].prototype = Storage::ImportedType{"Object"}; - ASSERT_THROW(storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::PrototypeChainCycle); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::PrototypeChainCycle); } TEST_F(ProjectStorage, ThrowForTypeIdAndPrototypeIdAreTheSameForRelinking) { - Storage::Types types{createTypesWithExportedTypeNamesOnly()}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].prototype = Storage::ImportedType{"Item"}; - types[1].typeName = "QObject2"; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[1].prototype = Storage::ImportedType{"Item"}; + package.types[1].typeName = "QObject2"; importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), QmlDesigner::PrototypeChainCycle); } TEST_F(ProjectStorage, RecursiveAliases) { - Storage::Types types{createTypesWithRecursiveAliases()}; + auto package{createSynchronizationPackageWithRecursiveAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf(IsStorageType(sourceId5, @@ -3262,22 +2702,12 @@ TEST_F(ProjectStorage, RecursiveAliases) TEST_F(ProjectStorage, RecursiveAliasesChangePropertyType) { - Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; + auto package{createSynchronizationPackageWithRecursiveAliases()}; + storage.synchronize(package); + package.types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; importsSourceId2.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf(IsStorageType(sourceId5, @@ -3293,25 +2723,15 @@ TEST_F(ProjectStorage, RecursiveAliasesChangePropertyType) TEST_F(ProjectStorage, UpdateAliasesAfterInjectingProperty) { - Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[0].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithRecursiveAliases()}; + storage.synchronize(package); + package.types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"Item"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.types[0]}, {sourceId1}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf(IsStorageType(sourceId5, @@ -3328,26 +2748,16 @@ TEST_F(ProjectStorage, UpdateAliasesAfterInjectingProperty) TEST_F(ProjectStorage, UpdateAliasesAfterChangeAliasToProperty) { - Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[2].propertyDeclarations.clear(); - types[2].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithRecursiveAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations.clear(); + package.types[2].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"Item"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(importsSourceId3, {types[2]}, {sourceId3}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId3, {package.types[2]}, {sourceId3}}); ASSERT_THAT(storage.fetchTypes(), AllOf(Contains(AllOf(IsStorageType(sourceId5, @@ -3376,26 +2786,16 @@ TEST_F(ProjectStorage, UpdateAliasesAfterChangeAliasToProperty) TEST_F(ProjectStorage, UpdateAliasesAfterChangePropertyToAlias) { - Storage::Types types{createTypesWithRecursiveAliases()}; - types[3].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList - | Storage::PropertyDeclarationTraits::IsReadOnly; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations.clear(); - types[1].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithRecursiveAliases()}; + package.types[3].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly; + storage.synchronize(package); + package.types[1].propertyDeclarations.clear(); + package.types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"Object2"}, "objects"}); importsSourceId2.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); - storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf(IsStorageType(sourceId5, @@ -3413,68 +2813,45 @@ TEST_F(ProjectStorage, UpdateAliasesAfterChangePropertyToAlias) TEST_F(ProjectStorage, CheckForProtoTypeCycleThrows) { - Storage::Types types{createTypesWithRecursiveAliases()}; - types[1].propertyDeclarations.clear(); - types[1].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithRecursiveAliases()}; + package.types[1].propertyDeclarations.clear(); + package.types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"AliasItem2"}, "objects"}); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - ASSERT_THROW(storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::AliasChainCycle); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::AliasChainCycle); } TEST_F(ProjectStorage, CheckForProtoTypeCycleAfterUpdateThrows) { - Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations.clear(); - types[1].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithRecursiveAliases()}; + storage.synchronize(package); + package.types[1].propertyDeclarations.clear(); + package.types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", Storage::ImportedType{"AliasItem2"}, "objects"}); importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), QmlDesigner::AliasChainCycle); } TEST_F(ProjectStorage, QualifiedPrototype) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qmlModuleId, - Storage::Version{}, - sourceId1}}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{qtQuickModuleId, "Object"}}}); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qmlModuleId, + Storage::Version{}, + sourceId1}}; + package.types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.sourceIds.push_back(sourceId3); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId1, @@ -3485,42 +2862,31 @@ TEST_F(ProjectStorage, QualifiedPrototype) TEST_F(ProjectStorage, QualifiedPrototypeUpperDownTheModuleChainThrows) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qtQuickModuleId, - Storage::Version{}, - sourceId1}}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qtQuickModuleId, + Storage::Version{}, + sourceId1}}; - ASSERT_THROW(storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qtQuickModuleId, - Storage::Version{}, - sourceId1}}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{qtQuickModuleId, "Object"}}}); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qtQuickModuleId, + Storage::Version{}, + sourceId1}}; + package.types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.sourceIds.push_back(sourceId3); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId1, @@ -3531,47 +2897,36 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain) TEST_F(ProjectStorage, QualifiedPrototypeWithWrongVersionThrows) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qmlModuleId, - Storage::Version{4}, - sourceId1}}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{qtQuickModuleId, "Object"}}}); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qmlModuleId, + Storage::Version{4}, + sourceId1}}; + package.types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.sourceIds.push_back(sourceId3); - ASSERT_THROW(storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, QualifiedPrototypeWithVersion) { - Storage::Types types{createTypes()}; - imports[0].version = Storage::Version{2}; - types[0].prototype = Storage::QualifiedImportedType{"Object", imports[0]}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{qtQuickModuleId, "Object"}}}); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + auto package{createSimpleSynchronizationPackage()}; + package.imports[0].version = Storage::Version{2}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", package.imports[0]}; + package.types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.sourceIds.push_back(sourceId3); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId1, @@ -3582,23 +2937,20 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersion) TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain) { - Storage::Types types{createTypes()}; - imports[2].version = Storage::Version{2}; - types[0].prototype = Storage::QualifiedImportedType{"Object", imports[2]}; - types[0].exportedTypes[0].version = Storage::Version{2}; - types.push_back( + auto package{createSimpleSynchronizationPackage()}; + package.imports[2].version = Storage::Version{2}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", package.imports[2]}; + package.types[0].exportedTypes[0].version = Storage::Version{2}; + package.types.push_back( Storage::Type{"QQuickObject", Storage::ImportedType{}, TypeAccessSemantics::Reference, sourceId3, {Storage::ExportedType{qtQuickModuleId, "Object", Storage::Version{2}}}}); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.sourceIds.push_back(sourceId3); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId1, @@ -3609,41 +2961,29 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain) TEST_F(ProjectStorage, QualifiedPrototypeWithVersionDownTheProtoTypeChainThrows) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{qtQuickModuleId, - Storage::Version{2}, - sourceId1}}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qtQuickModuleId, + Storage::Version{2}, + sourceId1}}; - ASSERT_THROW(storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{qtQuickModuleId, "Object"}}}); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.sourceIds.push_back(sourceId3); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains( @@ -3655,39 +2995,27 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName) TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameDownTheModuleChainThrows) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - ASSERT_THROW(storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameInTheModuleChain) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{"QQuickObject", - Storage::ImportedType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{qtQuickModuleId, "Object"}}}); - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.types.push_back(Storage::Type{"QQuickObject", + Storage::ImportedType{}, + TypeAccessSemantics::Reference, + sourceId3, + {Storage::ExportedType{qtQuickModuleId, "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.sourceIds.push_back(sourceId3); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains( @@ -3699,16 +3027,12 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameInTheModuleChain) TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameWithVersion) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object", Storage::Import{qmlModuleId, Storage::Version{2}, sourceId1}}; - imports.emplace_back(qmlModuleId, Storage::Version{2}, sourceId1); + package.imports.emplace_back(qmlModuleId, Storage::Version{2}, sourceId1); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains( @@ -3720,36 +3044,29 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameWithVersion) TEST_F(ProjectStorage, ChangePropertyTypeModuleIdWithQualifiedTypeThrows) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].exportedTypes[0].moduleId = qtQuickModuleId; + storage.synchronize(package); + package.types[1].exportedTypes[0].moduleId = qtQuickModuleId; - ASSERT_THROW(storage.synchronize(importsSourceId2, {types[1]}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, ChangePropertyTypeModuleIdWithQualifiedType) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + storage.synchronize(package); + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - types[1].exportedTypes[0].moduleId = qtQuickModuleId; - imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); + package.types[1].exportedTypes[0].moduleId = qtQuickModuleId; + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - storage.synchronize(imports, types, {sourceId1, sourceId2}, {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf(IsStorageType(sourceId1, @@ -3768,7 +3085,7 @@ TEST_F(ProjectStorage, AddFileStatuses) FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}, {fileStatus1, fileStatus2}}); ASSERT_THAT(convert(storage.fetchAllFileStatuses()), UnorderedElementsAre(fileStatus1, fileStatus2)); @@ -3778,9 +3095,9 @@ TEST_F(ProjectStorage, RemoveFileStatus) { FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}, {fileStatus1, fileStatus2}}); - storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1}); + storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}, {fileStatus1}}); ASSERT_THAT(convert(storage.fetchAllFileStatuses()), UnorderedElementsAre(fileStatus1)); } @@ -3790,9 +3107,9 @@ TEST_F(ProjectStorage, UpdateFileStatus) FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; FileStatus fileStatus2b{sourceId2, 102, 102}; - storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}, {fileStatus1, fileStatus2}}); - storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2b}); + storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}, {fileStatus1, fileStatus2b}}); ASSERT_THAT(convert(storage.fetchAllFileStatuses()), UnorderedElementsAre(fileStatus1, fileStatus2b)); @@ -3802,7 +3119,7 @@ TEST_F(ProjectStorage, ThrowForInvalidSourceId) { FileStatus fileStatus1{SourceId{}, 100, 100}; - ASSERT_THROW(storage.synchronize({}, {}, {sourceId1}, {fileStatus1}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{sourceId1}, {fileStatus1}}), Sqlite::ConstraintPreventsModification); } @@ -3810,7 +3127,7 @@ TEST_F(ProjectStorage, FetchAllFileStatuses) { FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}, {fileStatus1, fileStatus2}}); auto fileStatuses = convert(storage.fetchAllFileStatuses()); @@ -3821,7 +3138,7 @@ TEST_F(ProjectStorage, FetchAllFileStatusesReverse) { FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus2, fileStatus1}); + storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}, {fileStatus2, fileStatus1}}); auto fileStatuses = convert(storage.fetchAllFileStatuses()); @@ -3832,7 +3149,7 @@ TEST_F(ProjectStorage, FetchFileStatus) { FileStatus fileStatus1{sourceId1, 100, 100}; FileStatus fileStatus2{sourceId2, 101, 101}; - storage.synchronize({}, {}, {sourceId1, sourceId2}, {fileStatus1, fileStatus2}); + storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}, {fileStatus1, fileStatus2}}); auto fileStatus = storage.fetchFileStatus(sourceId1); @@ -3841,21 +3158,12 @@ TEST_F(ProjectStorage, FetchFileStatus) TEST_F(ProjectStorage, SynchronizeTypesWithoutTypeName) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].typeName.clear(); - types[3].prototype = Storage::ImportedType{"Object"}; + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); + package.types[3].typeName.clear(); + package.types[3].prototype = Storage::ImportedType{"Object"}; - storage.synchronize(importsSourceId4, {types[3]}, {sourceId4}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId4, {package.types[3]}, {sourceId4}}); ASSERT_THAT(storage.fetchTypes(), Contains(AllOf(IsStorageType(sourceId4, @@ -3869,11 +3177,8 @@ TEST_F(ProjectStorage, SynchronizeTypesWithoutTypeName) TEST_F(ProjectStorage, FetchByMajorVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Object"}, TypeAccessSemantics::Reference, @@ -3881,7 +3186,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionForImportedType) {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{1}, sourceId2}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -3892,11 +3197,8 @@ TEST_F(ProjectStorage, FetchByMajorVersionForImportedType) TEST_F(ProjectStorage, FetchByMajorVersionForQualifiedImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{1}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Object", import}, @@ -3904,7 +3206,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionForQualifiedImportedType) sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -3915,11 +3217,8 @@ TEST_F(ProjectStorage, FetchByMajorVersionForQualifiedImportedType) TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, @@ -3927,7 +3226,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForImportedType) {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{1, 2}, sourceId2}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -3938,11 +3237,8 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForImportedType) TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{1, 2}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, @@ -3950,7 +3246,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedTyp sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -3962,11 +3258,8 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedTyp TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForImportedTypeIfMinorVersionIsNotExportedThrows) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Object"}, TypeAccessSemantics::Reference, @@ -3974,18 +3267,15 @@ TEST_F(ProjectStorage, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2}; - ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedTypeIfMinorVersionIsNotExportedThrows) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Object", import}, @@ -3993,17 +3283,14 @@ TEST_F(ProjectStorage, sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchLowMinorVersionForImportedTypeThrows) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, @@ -4011,17 +3298,14 @@ TEST_F(ProjectStorage, FetchLowMinorVersionForImportedTypeThrows) {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2}; - ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchLowMinorVersionForQualifiedImportedTypeThrows) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, @@ -4029,17 +3313,14 @@ TEST_F(ProjectStorage, FetchLowMinorVersionForQualifiedImportedTypeThrows) sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchHigherMinorVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, @@ -4047,7 +3328,7 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForImportedType) {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{1, 3}, sourceId2}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4058,11 +3339,8 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForImportedType) TEST_F(ProjectStorage, FetchHigherMinorVersionForQualifiedImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{1, 3}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, @@ -4070,7 +3348,7 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForQualifiedImportedType) sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4081,11 +3359,8 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForQualifiedImportedType) TEST_F(ProjectStorage, FetchDifferentMajorVersionForImportedTypeThrows) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, @@ -4093,17 +3368,14 @@ TEST_F(ProjectStorage, FetchDifferentMajorVersionForImportedTypeThrows) {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{3, 1}, sourceId2}; - ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchDifferentMajorVersionForQualifiedImportedTypeThrows) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{3, 1}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, @@ -4111,17 +3383,14 @@ TEST_F(ProjectStorage, FetchDifferentMajorVersionForQualifiedImportedTypeThrows) sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - ASSERT_THROW(storage.synchronize({import}, {type}, {sourceId2}, {}), + ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, @@ -4129,7 +3398,7 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForImportedType) {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{2, 3}, sourceId2}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4140,11 +3409,8 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForImportedType) TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForQualifiedImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{2, 3}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, @@ -4152,7 +3418,7 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForQualifiedImportedType) sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4163,11 +3429,8 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForQualifiedImportedType) TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, @@ -4175,7 +3438,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForImportedType {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{}, sourceId2}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4186,11 +3449,8 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForImportedType TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForQualifiedImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, @@ -4198,7 +3458,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForQualifiedImp sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4209,11 +3469,8 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForQualifiedImp TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"Obj"}, TypeAccessSemantics::Reference, @@ -4221,7 +3478,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForImportedTy {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{2}, sourceId2}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4232,11 +3489,8 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForImportedTy TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForQualifiedImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{2}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"Obj", import}, @@ -4244,7 +3498,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForQualifiedI sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4255,11 +3509,8 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForQualifiedI TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Type type{"Item", Storage::ImportedType{"BuiltInObj"}, TypeAccessSemantics::Reference, @@ -4267,7 +3518,7 @@ TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForImportedType) {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; Storage::Import import{qmlModuleId, Storage::Version{}, sourceId2}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4278,11 +3529,8 @@ TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForImportedType) TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForQualifiedImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); Storage::Import import{qmlModuleId, Storage::Version{}, sourceId2}; Storage::Type type{"Item", Storage::QualifiedImportedType{"BuiltInObj", import}, @@ -4290,7 +3538,7 @@ TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForQualifiedImportedT sourceId2, {Storage::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}}; - storage.synchronize({import}, {type}, {sourceId2}, {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}); ASSERT_THAT(storage.fetchTypes(), Contains(IsStorageType(sourceId2, @@ -4310,34 +3558,23 @@ TEST_F(ProjectStorage, EnsureThatPropertiesForRemovedTypesAreNotAnymoreRelinked) Storage::ImportedType{"Object"}, Storage::PropertyDeclarationTraits::IsList}}}; Storage::Import import{qmlModuleId, Storage::Version{}, sourceId1}; - storage.synchronize({import}, - {type}, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId1}}); - ASSERT_NO_THROW(storage.synchronize({}, {}, {sourceId1}, {})); + ASSERT_NO_THROW(storage.synchronize(SynchronizationPackage{{sourceId1}})); } TEST_F(ProjectStorage, EnsureThatPrototypesForRemovedTypesAreNotAnymoreRelinked) { - auto types = createTypes(); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); - ASSERT_NO_THROW(storage.synchronize({}, {}, {sourceId1, sourceId2}, {})); + ASSERT_NO_THROW(storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}})); } TEST_F(ProjectStorage, MinimalUpdates) { - auto types = createTypes(); - storage.synchronize( - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); Storage::Type quickType{"QQuickItem", {}, TypeAccessSemantics::Reference, @@ -4350,7 +3587,7 @@ TEST_F(ProjectStorage, MinimalUpdates) {}, Storage::ChangeLevel::Minimal}; - storage.synchronize({}, {quickType}, {}, {}); + storage.synchronize(SynchronizationPackage{{quickType}}); ASSERT_THAT( storage.fetchTypes(), diff --git a/tests/unit/unittest/projectstoragemock.h b/tests/unit/unittest/projectstoragemock.h index 161a2a0fe1b..42de0b0b40a 100644 --- a/tests/unit/unittest/projectstoragemock.h +++ b/tests/unit/unittest/projectstoragemock.h @@ -36,13 +36,7 @@ class ProjectStorageMock : public QmlDesigner::ProjectStorageInterface { public: - MOCK_METHOD(void, - synchronize, - (QmlDesigner::Storage::Imports imports, - QmlDesigner::Storage::Types types, - QmlDesigner::SourceIds sourceIds, - QmlDesigner::FileStatuses fileStatuses), - (override)); + MOCK_METHOD(void, synchronize, (QmlDesigner::Storage::SynchronizationPackage package), (override)); MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (Utils::SmallStringView), (override)); diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp index d63448063d4..c26aaa7b70a 100644 --- a/tests/unit/unittest/projectstorageupdater-test.cpp +++ b/tests/unit/unittest/projectstorageupdater-test.cpp @@ -47,6 +47,7 @@ using QmlDesigner::SourceId; using QmlDesigner::Storage::TypeAccessSemantics; namespace Storage = QmlDesigner::Storage; using QmlDesigner::IdPaths; +using QmlDesigner::Storage::SynchronizationPackage; using QmlDesigner::Storage::Version; MATCHER_P4(IsStorageType, @@ -106,6 +107,14 @@ MATCHER_P3(IsFileStatus, && fileStatus.lastModified == lastModified; } +MATCHER(PackageIsEmpty, std::string(negation ? "isn't empty" : "is empty")) +{ + const Storage::SynchronizationPackage &package = arg; + + return package.imports.empty() && package.types.empty() && package.fileStatuses.empty() + && package.sourceIds.empty(); +} + class ProjectStorageUpdater : public testing::Test { public: @@ -317,7 +326,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange) ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId))) .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421})); - EXPECT_CALL(projectStorageMock, synchronize(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty())); + EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); updater.update(); } @@ -338,11 +347,14 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes) EXPECT_CALL(projectStorageMock, moduleId(Eq("Example"))); EXPECT_CALL(projectStorageMock, - synchronize(ElementsAre(import), - ElementsAre(Eq(objectType)), - UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId), - UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), - IsFileStatus(qmltypesPathSourceId, 21, 421)))); + synchronize( + AllOf(Field(&SynchronizationPackage::imports, ElementsAre(import)), + Field(&SynchronizationPackage::types, ElementsAre(Eq(objectType))), + Field(&SynchronizationPackage::sourceIds, + UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId)), + Field(&SynchronizationPackage::fileStatuses, + UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), + IsFileStatus(qmltypesPathSourceId, 21, 421)))))); updater.update(); } @@ -361,7 +373,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged) ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId))) .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421})); - EXPECT_CALL(projectStorageMock, synchronize(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty())); + EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); updater.update(); } @@ -410,34 +422,38 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments) EXPECT_CALL( projectStorageMock, - synchronize(UnorderedElementsAre(import1, import2, import3), - UnorderedElementsAre( - AllOf(IsStorageType("First.qml", - Storage::ImportedType{"Object"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId1), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), - AllOf(IsStorageType("First.2.qml", - Storage::ImportedType{"Object2"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId2), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))), - AllOf(IsStorageType("Second.qml", - Storage::ImportedType{"Object3"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId3), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2))))), - UnorderedElementsAre(qmlDirPathSourceId, - qmlDocumentSourceId1, - qmlDocumentSourceId2, - qmlDocumentSourceId3), - UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), - IsFileStatus(qmlDocumentSourceId1, 22, 12), - IsFileStatus(qmlDocumentSourceId2, 22, 13), - IsFileStatus(qmlDocumentSourceId3, 22, 14)))); + synchronize(AllOf( + Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2, import3)), + Field(&SynchronizationPackage::types, + UnorderedElementsAre( + AllOf(IsStorageType("First.qml", + Storage::ImportedType{"Object"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId1), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), + AllOf(IsStorageType("First.2.qml", + Storage::ImportedType{"Object2"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId2), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))), + AllOf(IsStorageType("Second.qml", + Storage::ImportedType{"Object3"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId3), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2)))))), + Field(&SynchronizationPackage::sourceIds, + UnorderedElementsAre(qmlDirPathSourceId, + qmlDocumentSourceId1, + qmlDocumentSourceId2, + qmlDocumentSourceId3)), + Field(&SynchronizationPackage::fileStatuses, + UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), + IsFileStatus(qmlDocumentSourceId1, 22, 12), + IsFileStatus(qmlDocumentSourceId2, 22, 13), + IsFileStatus(qmlDocumentSourceId3, 22, 14)))))); updater.update(); } @@ -452,24 +468,28 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate) EXPECT_CALL( projectStorageMock, - synchronize(UnorderedElementsAre(import1, import2), - UnorderedElementsAre( - AllOf(IsStorageType("First.qml", - Storage::ImportedType{"Object"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId1), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), - AllOf(IsStorageType("First.2.qml", - Storage::ImportedType{"Object2"}, - TypeAccessSemantics::Reference, - qmlDocumentSourceId2), - Field(&Storage::Type::exportedTypes, - ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2))))), - UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2), - UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), - IsFileStatus(qmlDocumentSourceId1, 22, 12), - IsFileStatus(qmlDocumentSourceId2, 22, 13)))); + synchronize(AllOf( + Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2)), + Field(&SynchronizationPackage::types, + UnorderedElementsAre( + AllOf(IsStorageType("First.qml", + Storage::ImportedType{"Object"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId1), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), + AllOf(IsStorageType("First.2.qml", + Storage::ImportedType{"Object2"}, + TypeAccessSemantics::Reference, + qmlDocumentSourceId2), + Field(&Storage::Type::exportedTypes, + ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))))), + Field(&SynchronizationPackage::sourceIds, + UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)), + Field(&SynchronizationPackage::fileStatuses, + UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), + IsFileStatus(qmlDocumentSourceId1, 22, 12), + IsFileStatus(qmlDocumentSourceId2, 22, 13)))))); updater.update(); } From 7e62840ec1021d3118e36ab7fb8a5b484bb9f2a8 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 20 Oct 2021 19:06:02 +0200 Subject: [PATCH 116/117] CMake: Define BUILD_WITH_PCH before usage On Windows QtCreatorAPIInternal.cmake would contain a check for BUILD_WITH_PCH and if not set add a few defines to the DEFAULT_DEFINES. First time the BUILD_WITH_PCH would not be set, because the option will be set later, the DEFAULT_DEFINES will contain the specific non-pch defines. The second time BUILD_WITH_PCH would be ON and those non-pch specific DEFAULT_DEFINES will be removed, and the build system has to do a full rebuild because the defines changed. Change-Id: I3f039a91667affc35f18103cfed062481f9dc93e Reviewed-by: Marco Bubke Reviewed-by: Tim Jenssen --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 87be55233dd..8911572ca09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.10) ## Add paths to check for cmake modules: list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +option(BUILD_WITH_PCH "Build with precompiled headers" ON) + include(FeatureSummary) include(QtCreatorIDEBranding RESULT_VARIABLE IDE_BRANDING_FILE) include(QtCreatorTranslations) @@ -67,8 +69,6 @@ endif() find_package(Qt5 COMPONENTS LinguistTools QUIET) find_package(Qt5 COMPONENTS Quick QuickWidgets Designer DesignerComponents Help SerialPort Svg Tools QUIET) -option(BUILD_WITH_PCH "Build with precompiled headers" ON) - find_package(Threads) find_package(Clang QUIET) find_package(KF5SyntaxHighlighting QUIET) From 5377253612801b2f92e0b55e40c3ce0dd2574b09 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Wed, 20 Oct 2021 22:50:08 +0200 Subject: [PATCH 117/117] qmlpreview: use empty messageReceived() Default implementation already does not react on it. Change-Id: Ieaca8ab0a700b9626a705567f228bdc05172c188 Reviewed-by: Tim Jenssen --- src/plugins/qmlpreview/qmldebugtranslationclient.cpp | 8 -------- src/plugins/qmlpreview/qmldebugtranslationclient.h | 2 -- 2 files changed, 10 deletions(-) diff --git a/src/plugins/qmlpreview/qmldebugtranslationclient.cpp b/src/plugins/qmlpreview/qmldebugtranslationclient.cpp index e383784ef59..5d488772656 100644 --- a/src/plugins/qmlpreview/qmldebugtranslationclient.cpp +++ b/src/plugins/qmlpreview/qmldebugtranslationclient.cpp @@ -52,14 +52,6 @@ void QmlDebugTranslationClient::changeLanguage(const QUrl &url, const QString &l } -void QmlDebugTranslationClient::messageReceived(const QByteArray &data) -{ - QmlDebug::QPacket packet(dataStreamVersion(), data); - qint8 command; - packet >> command; - qDebug() << Q_FUNC_INFO << "invalid command" << command; -} - void QmlDebugTranslationClient::stateChanged(QmlDebug::QmlDebugClient::State state) { if (state == Unavailable) diff --git a/src/plugins/qmlpreview/qmldebugtranslationclient.h b/src/plugins/qmlpreview/qmldebugtranslationclient.h index 0b9e3594b2b..8a6bc1478fb 100644 --- a/src/plugins/qmlpreview/qmldebugtranslationclient.h +++ b/src/plugins/qmlpreview/qmldebugtranslationclient.h @@ -37,8 +37,6 @@ public: explicit QmlDebugTranslationClient(QmlDebug::QmlDebugConnection *connection); void changeLanguage(const QUrl &url, const QString &localeIsoCode); - - void messageReceived(const QByteArray &message) override; void stateChanged(State state) override; signals: