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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 162b0a9aeee..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) @@ -49,8 +51,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,9 +67,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) - -option(BUILD_WITH_PCH "Build with precompiled headers" ON) +find_package(Qt5 COMPONENTS Quick QuickWidgets Designer DesignerComponents Help SerialPort Svg Tools QUIET) find_package(Threads) find_package(Clang QUIET) 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/qml-export-gimp.png b/doc/qtcreator/images/qml-export-gimp.png deleted file mode 100644 index 5c78a4013bb..00000000000 Binary files a/doc/qtcreator/images/qml-export-gimp.png and /dev/null differ 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 c7d35b0db38..00000000000 Binary files a/doc/qtcreator/images/qml-observer-context-menu.png and /dev/null differ diff --git a/doc/qtcreator/images/qmldesigner-backends-add.png b/doc/qtcreator/images/qmldesigner-backends-add.png deleted file mode 100644 index a11ad9923c6..00000000000 Binary files a/doc/qtcreator/images/qmldesigner-backends-add.png and /dev/null differ diff --git a/doc/qtcreator/images/qmldesigner-backends.png b/doc/qtcreator/images/qmldesigner-backends.png deleted file mode 100644 index f5eb6c26bc9..00000000000 Binary files a/doc/qtcreator/images/qmldesigner-backends.png and /dev/null differ diff --git a/doc/qtcreator/images/qmldesigner-new-project.png b/doc/qtcreator/images/qmldesigner-new-project.png index 8554f7af892..7bab02c38f1 100644 Binary files a/doc/qtcreator/images/qmldesigner-new-project.png and b/doc/qtcreator/images/qmldesigner-new-project.png differ 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 b59b319b1b1..00000000000 Binary files a/doc/qtcreator/images/qtcreator-iso-icon-browser.png and /dev/null differ diff --git a/doc/qtcreator/images/qtcreator-live-preview.png b/doc/qtcreator/images/qtcreator-live-preview.png index 91d505dce91..4fd62939ab8 100644 Binary files a/doc/qtcreator/images/qtcreator-live-preview.png and b/doc/qtcreator/images/qtcreator-live-preview.png differ 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 a2a5bf396fc..d9d7509a8ad 100644 Binary files a/doc/qtcreator/images/qtcreator-new-qt-quick-project-wizard.png and b/doc/qtcreator/images/qtcreator-new-qt-quick-project-wizard.png differ diff --git a/doc/qtcreator/images/qtcreator-new-subproject.png b/doc/qtcreator/images/qtcreator-new-subproject.png index e65a09bee68..7bab02c38f1 100644 Binary files a/doc/qtcreator/images/qtcreator-new-subproject.png and b/doc/qtcreator/images/qtcreator-new-subproject.png differ 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 2d06ea84b40..00000000000 Binary files a/doc/qtcreator/images/qtcreator-qt-quick-editors.png and /dev/null differ 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 9b1c8bb3b34..9be304d7165 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/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/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-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-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/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] */ 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 42455f44004..47028e00a23 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 @@ -56,8 +60,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/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 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 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)) 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 1dae931af30..d40d1821268 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -777,6 +777,8 @@ void QuickItemNodeInstance::reparent(const ObjectNodeInstance::Pointer &oldParen setMovable(true); } + markRepeaterParentDirty(); + ObjectNodeInstance::reparent(oldParentInstance, oldParentProperty, newParentInstance, newParentProperty); if (!newParentInstance) @@ -841,6 +843,8 @@ void QuickItemNodeInstance::setPropertyVariant(const PropertyName &name, const Q if (name == "layer.enabled" || name == "layer.effect") setAllNodesDirtyRecursive(quickItem()); + markRepeaterParentDirty(); + ObjectNodeInstance::setPropertyVariant(name, value); refresh(); @@ -860,6 +864,8 @@ void QuickItemNodeInstance::setPropertyBinding(const PropertyName &name, const Q if (name.startsWith("anchors.") && isRootNodeInstance()) return; + markRepeaterParentDirty(); + ObjectNodeInstance::setPropertyBinding(name, expression); refresh(); @@ -937,6 +943,8 @@ void QuickItemNodeInstance::resetProperty(const PropertyName &name) resetVertical(); } + markRepeaterParentDirty(); + ObjectNodeInstance::resetProperty(name); if (isInLayoutable()) @@ -1013,6 +1021,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; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 2aa17d9e2b7..97b5031260c 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()); @@ -498,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/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/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/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/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..4de51ba7c89 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; @@ -284,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) @@ -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; @@ -650,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) @@ -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/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..f4e88b719a7 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
@@ -651,7 +728,11 @@ MatchResult RegExpr::doMatch(const QString &text, int offset, const QStringList
     /**
      * 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
@@ -683,16 +764,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 +785,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",
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/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,
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/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/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
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/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/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/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/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/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/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;
 
diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp
index fd68683acee..065f96809e9 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;
@@ -1280,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 409421eaf58..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;
@@ -161,6 +162,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;
@@ -198,6 +202,11 @@ private:
 
 using FilePaths = QList;
 
+inline QHashValueType qHash(const Utils::FilePath &a, uint seed = 0)
+{
+    return a.hash(seed);
+}
+
 } // namespace Utils
 
 QT_BEGIN_NAMESPACE
@@ -205,3 +214,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 a92017f7709..c87ca5d5dd0 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;
@@ -314,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
-
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/libs/utils/mimetypes/mimeglobpattern.cpp b/src/libs/utils/mimetypes/mimeglobpattern.cpp
index 9ab335b862a..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,55 +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();
 
-    const int starCount = m_pattern.count(QLatin1Char('*'));
+    switch (m_patternType) {
+    case SuffixPattern: {
+        if (fileNameLength + 1 < patternLength)
+            return false;
 
-    // Patterns like "*~", "*.extension"
-    if (m_pattern[0] == QLatin1Char('*') && m_pattern.indexOf(QLatin1Char('[')) == -1 && 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;
+        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 (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;
+    case PrefixPattern: {
+        if (fileNameLength + 1 < patternLength)
+            return false;
 
         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_pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 0 && m_pattern.indexOf(QLatin1Char('?')))
-        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 ecbfb02ce9d..990a5b07d2f 100644
--- a/src/libs/utils/mimetypes/mimeglobpattern_p.h
+++ b/src/libs/utils/mimetypes/mimeglobpattern_p.h
@@ -73,16 +73,27 @@ 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_caseSensitivity(s),
+        m_patternType(detectPatternType(m_pattern))
     {
-        if (s == Qt::CaseInsensitive) {
-            m_pattern = m_pattern.toLower();
-        }
     }
-    ~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; }
@@ -90,10 +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;
     Qt::CaseSensitivity m_caseSensitivity;
+    PatternType m_patternType;
 };
 
 class MimeGlobPatternList : public QList
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/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/tests/unit/unittest/qmldom-test.cpp b/src/libs/utils/threadutils.cpp
similarity index 66%
rename from tests/unit/unittest/qmldom-test.cpp
rename to src/libs/utils/threadutils.cpp
index b7e8557f10e..7d10199c4ab 100644
--- a/tests/unit/unittest/qmldom-test.cpp
+++ b/src/libs/utils/threadutils.cpp
@@ -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,16 @@
 **
 ****************************************************************************/
 
-#include "googletest.h"
+#include "threadutils.h"
 
-// cast of the top level items (DomEnvironments,...)
-#include 
+#include 
+#include 
 
-// everything is in the QQmlJS::Dom namespace
-using namespace QQmlJS::Dom;
+namespace Utils {
 
-namespace {
-
-class QmlDom : public ::testing::Test
+bool isMainThread()
 {
-public:
-//    static void SetUpTestCase();
-//    static void TearDownTestCase();
-
-protected:
-};
-
-TEST_F(QmlDom, First)
-{
-    DomItem env = DomEnvironment::create({}, DomEnvironment::Option::SingleThreaded
-                                             | DomEnvironment::Option::NoDependencies);
+    return QThread::currentThread() == qApp->thread();
 }
 
-} // anonymous
+} // namespace Utils
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h b/src/libs/utils/threadutils.h
similarity index 84%
rename from src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h
rename to src/libs/utils/threadutils.h
index a39adb5ed6f..cc59658c277 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h
+++ b/src/libs/utils/threadutils.h
@@ -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 Qt Creator.
@@ -25,10 +25,11 @@
 
 #pragma once
 
-#include 
+#include "utils_global.h"
+
+namespace Utils {
+
+QTCREATOR_UTILS_EXPORT bool isMainThread();
+
+} // namespace Utils
 
-#if defined(KSYNTAXHIGHLIGHTING_LIBRARY)
-#  define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_EXPORT
-#else
-#  define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_IMPORT
-#endif
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/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp
index c769a744d26..7bc1c6310d3 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");
@@ -562,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) {
@@ -597,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"))
@@ -633,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;
@@ -649,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();
@@ -690,15 +708,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
@@ -742,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;
 
@@ -751,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;
@@ -782,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 09f7ac85f1d..2fc22ddbc2e 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);
@@ -144,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;
 
@@ -171,16 +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/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);
 
diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp
index bba148dda86..ea4ddbf8e16 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();
     }});
 
@@ -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
@@ -614,8 +618,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/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;
 }
 
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 =
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/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp
index c576571d32c..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();
@@ -133,7 +131,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 +510,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/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp
index 2f83e86156c..2d0e7af83e4 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::AlignRight;
 
     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 {
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/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/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 5b3e76bee8b..2b6044f3ac3 100644
--- a/src/plugins/clangcodemodel/clangdclient.cpp
+++ b/src/plugins/clangcodemodel/clangdclient.cpp
@@ -94,8 +94,22 @@ 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)
+{
+    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:
@@ -277,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
     {
@@ -298,6 +364,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 +376,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;
@@ -685,20 +778,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);
@@ -1030,12 +1115,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;
 };
 
@@ -1048,6 +1135,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;
@@ -1643,7 +1731,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") {
@@ -2128,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();
@@ -2145,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;
@@ -2174,7 +2264,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"))
@@ -2210,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,
@@ -2222,13 +2313,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 +2344,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 +2359,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 +2378,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"))
@@ -2338,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(),
@@ -2378,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) {
@@ -2543,21 +2639,28 @@ ClangdClient::ClangdCompletionAssistProvider::ClangdCompletionAssistProvider(Cla
 {}
 
 IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor(
-    const AssistInterface *assistInterface) const
+    const AssistInterface *interface) const
 {
-    ClangCompletionContextAnalyzer contextAnalyzer(assistInterface->textDocument(),
-                                                   assistInterface->position(), false, {});
+    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(),
@@ -2565,9 +2668,11 @@ 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();
+    qCDebug(clangdLogCompletion) << "creating proper completion processor"
+                                 << (snippetsGroup.isEmpty() ? "without" : "with") << "snippets";
     return new ClangdCompletionAssistProcessor(m_client, snippetsGroup);
 }
 
@@ -2588,6 +2693,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;
@@ -2598,6 +2704,14 @@ bool ClangdClient::ClangdCompletionAssistProvider::isContinuationChar(const QCha
     return CppEditor::isValidIdentifierChar(c);
 }
 
+bool ClangdClient::ClangdCompletionAssistProvider::isInCommentOrString(
+        const AssistInterface *interface) const
+{
+    LanguageFeatures features = LanguageFeatures::defaultFeatures();
+    features.objCEnabled = CppEditor::ProjectFile::isObjC(interface->filePath().toString());
+    return CppEditor::isInCommentOrString(interface, features);
+}
+
 void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator,
                                  int /*basePosition*/) const
 {
@@ -2607,35 +2721,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.
@@ -2663,7 +2769,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) {
@@ -2679,7 +2785,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;
@@ -2701,9 +2807,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)
@@ -2806,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()
@@ -2881,7 +3005,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;
@@ -2891,7 +3015,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;
@@ -2926,6 +3050,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;
@@ -2969,16 +3095,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;
@@ -3155,8 +3279,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;
@@ -3255,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
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/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 52be361305a..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)); @@ -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/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; } 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 { 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/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/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; } 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()); }); 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/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); diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index cabac0b3b98..d5836605f48 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()); @@ -595,9 +611,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); @@ -730,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/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/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/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 6fa127e255b..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)) { @@ -1186,10 +1189,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 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) 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); 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; 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; 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/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; }; 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); 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, 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/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; } 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"); 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; 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 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: ;" 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, 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) { diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index debdcaafdd4..87d52ad74b1 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 @@ -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)); 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/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; } 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); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 8109a3f91ec..2251f4d9e6b 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3800,8 +3800,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(), sp.macroExpander->expand(it.value())); + } return rc; } @@ -3850,6 +3853,7 @@ void GdbEngine::setupEngine() gdbCommand.addArg("-n"); Environment gdbEnv = rp.debugger.environment; + gdbEnv.setupEnglishOutput(); if (rp.runAsRoot) { CommandLine wrapped("sudo", {"-A"}); wrapped.addCommandLineAsArgs(gdbCommand); 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) { } 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); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 638fb91db0e..4461c7a1e86 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}); } @@ -1069,6 +1062,19 @@ FilePath DockerDevice::mapToGlobalPath(const FilePath &pathOnDevice) const return result; } +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 = FilePath::fromString(globalPath.path()).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; @@ -1570,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 } 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/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 862dfc12b57..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); } @@ -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); @@ -8201,9 +8200,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 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 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/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; }; 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(); } 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/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) 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/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; 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/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() diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index ac73d2a0473..31155c276c0 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -87,6 +87,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; @@ -153,7 +154,131 @@ 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; + +#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; +} + +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; @@ -163,7 +288,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; @@ -180,21 +310,31 @@ 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) + subData = mergeDataValueMaps(specifiedSubData.toMap(), defaultSubData.toMap()); + else if (specifiedSubData.type() == QVariant::List) + subData = specifiedSubData; - QVariant subData = data.value(QLatin1String(DATA_KEY)); if (!factory->validateData(typeId, subData, errorMessage)) return p; @@ -209,6 +349,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; @@ -258,14 +401,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; } @@ -283,7 +424,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; } 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; 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(); } diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index a49011bc41f..b283862c467 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) { @@ -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()); } @@ -804,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); 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(); }); 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/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; } 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); 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/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/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/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index ce73af5161a..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 @@ -27,6 +28,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/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..eff90366a0a 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,26 @@ 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); + } +} + +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 diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h index 495462128f8..738d9c7101d 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 READ stateName WRITE setStateName) public: BindingEditor(QObject *parent = nullptr); @@ -64,15 +65,21 @@ 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(); + QString targetName() const; + QString stateName() const; + signals: void accepted(); void rejected(); @@ -93,6 +100,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/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 ab2853354c8..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 false; + 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/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()); }); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 10e1373dde2..187bc4ca17f 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -339,26 +339,13 @@ 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) +{ + Q_UNUSED(newNodeSource) + addOrRemoveFormEditorItem(node); } WidgetInfo FormEditorView::widgetInfo() @@ -863,6 +850,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; 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/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/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; 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 de15fde7cf3..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 @@ -560,45 +561,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 +603,30 @@ 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); + 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(' '))); + } } } 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/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/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/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/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; } 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/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/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(); diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 2a428c65332..5df23b73854 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,65 +56,73 @@ public: ProjectStorage(Database &database, bool isInitialized) : database{database} , initializer{database, isInitialized} - {} + { + moduleCache.populate(); + } - void synchronize(Storage::Modules modules, - Storage::Imports imports, - Storage::Types types, - SourceIds sourceIds, - FileStatuses fileStatuses) override + void synchronize(Storage::SynchronizationPackage package) 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()); + 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); - synchronizeModules(modules, typeIdsToBeDeleted, sourceIdValues); - synchronizeImports(imports, sourceIdValues); - synchronizeTypes(types, + synchronizeFileStatuses(package.fileStatuses, sourceIdValues); + synchronizeImports(package.imports, sourceIdValues); + synchronizeTypes(package.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 +143,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 +294,6 @@ public: return writeSourceId(sourceContextId, sourceName); } - auto fetchAllModules() const - { - return selectAllModulesStatement.template valuesWithTransaction(128); - } - auto fetchAllFileStatuses() const { return selectAllFileStatusesStatement.template rangeWithTransaction(); @@ -299,9 +305,79 @@ public: &sourceId); } - SourceIds fetchSourceDependencieIds(SourceId sourceId) const override { return {}; } + Storage::ProjectDatas fetchProjectDatas(SourceId sourceId) const override + { + return Storage::ProjectDatas{}; + } 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,55 @@ private: }; auto insert = [&](const Storage::ExportedType &type) { - if (type.version) { - upsertExportedTypeNamesWithVersionStatement.write(&type.moduleId, - type.name, - static_cast( - Storage::TypeNameKind::Exported), - type.version.major.value, - type.version.minor.value, - &type.typeId); + if (!type.moduleId) + throw QmlDesigner::ModuleDoesNotExists{}; - } else if (type.version.major) { - upsertExportedTypeNamesWithMajorVersionStatement - .write(&type.moduleId, - type.name, - static_cast(Storage::TypeNameKind::Exported), - type.version.major.value, - &type.typeId); - } else { - upsertExportedTypeNamesWithoutVersionStatement - .write(&type.moduleId, - type.name, - static_cast(Storage::TypeNameKind::Exported), - &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); + } + } catch (const Sqlite::ConstraintPreventsModification &) { + throw QmlDesigner::ModuleDoesNotExists{}; } }; 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 +985,7 @@ private: } void synchronizePropertyDeclarationsUpdateAlias( - std::vector &updatedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, const Storage::PropertyDeclarationView &view, const Storage::PropertyDeclaration &value, SourceId sourceId) @@ -887,7 +1000,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 +1020,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 +1062,12 @@ private: view, value, sourceId); + propertyDeclarationIds.push_back(view.id); } else { - synchronizePropertyDeclarationsUpdateProperty(view, value, sourceId); + synchronizePropertyDeclarationsUpdateProperty(view, + value, + sourceId, + propertyDeclarationIds); } }; @@ -962,14 +1081,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 +1117,7 @@ private: }); auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement - .template range(&typeId); + .template range(&type.typeId); auto compareKey = [](const AliasPropertyDeclarationView &view, const Storage::PropertyDeclaration &value) { @@ -1006,29 +1131,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) @@ -1096,7 +1216,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\":"); @@ -1257,60 +1377,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 +1486,7 @@ private: &propertyDeclarationId); } - void syncPrototypes(Storage::Type &type) + void syncPrototype(Storage::Type &type, TypeIds &typeIds) { if (type.changeLevel == Storage::ChangeLevel::Minimal) return; @@ -1358,22 +1506,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 +1601,6 @@ private: &typeNameId); } - if (kind == Storage::TypeNameKind::Native) - return selectTypeIdForNativeTypeNameNamesStatement.template value(&typeNameId); - return selectTypeIdForImportedTypeNameNamesStatement.template value(&typeNameId); } @@ -1649,21 +1807,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); @@ -1706,23 +1859,20 @@ 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 &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 +1973,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 +2007,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 +2076,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 +2100,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 +2227,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 +2380,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 +2390,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 +2415,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/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/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h index 302a1801a2d..7d27bd22f1d 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h @@ -33,15 +33,12 @@ namespace QmlDesigner { class ProjectStorageInterface { public: - virtual void synchronize(Storage::Modules modules, - 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; 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 50db7c48537..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 @@ -35,10 +36,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 @@ -121,38 +122,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) @@ -165,34 +134,36 @@ 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) - : name{name} - , version{version} + 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 + return first.moduleId == second.moduleId && first.version == second.version && first.sourceId == second.sourceId; } public: - Utils::PathString name; Version version; ModuleId moduleId; SourceId sourceId; + Utils::SmallString aliasName; }; using Imports = std::vector; @@ -269,6 +240,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} @@ -276,9 +253,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) @@ -299,6 +277,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, @@ -551,6 +534,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, @@ -563,13 +555,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} {} @@ -594,6 +597,7 @@ public: ImportedTypeName typeName; Utils::SmallString aliasPropertyName; PropertyDeclarationTraits traits = {}; + TypeId propertyTypeId; TypeId typeId; PropertyKind kind = PropertyKind::Property; }; @@ -632,8 +636,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, @@ -650,37 +653,42 @@ public: , functionDeclarations{std::move(functionDeclarations)} , signalDeclarations{std::move(signalDeclarations)} , enumerationDeclarations{std::move(enumerationDeclarations)} - , moduleId{moduleId} , accessSemantics{accessSemantics} , sourceId{sourceId} , 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) : typeName{typeName} , prototype{NativeType{prototype}} - , moduleId{moduleId} , accessSemantics{static_cast(accessSemantics)} , sourceId{sourceId} {} - 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}} - , moduleId{moduleId} , accessSemantics{static_cast(accessSemantics)} , sourceId{sourceId} , typeId{typeId} + , prototypeId{prototypeId} {} friend bool operator==(const Type &first, const Type &second) noexcept @@ -690,7 +698,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; } @@ -702,31 +709,52 @@ public: FunctionDeclarations functionDeclarations; SignalDeclarations signalDeclarations; EnumerationDeclarations enumerationDeclarations; - TypeAccessSemantics accessSemantics = TypeAccessSemantics::Invalid; + TypeAccessSemantics accessSemantics = TypeAccessSemantics::None; SourceId sourceId; TypeId typeId; - ModuleId moduleId; + TypeId prototypeId; ChangeLevel changeLevel = ChangeLevel::Full; }; using Types = std::vector; -class ModuleView +class ProjectData { 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; + ModuleId extraModuleId; SourceId sourceId; }; +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 b5a7945181f..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)}; @@ -117,44 +104,37 @@ 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); + Storage::ProjectData projectData{ModuleId{}, sourceId}; + + parseTypeInfo(projectData, qmltypesPath, package); } } -void ProjectUpdater::parseTypeInfos(const SourceIds &qmltypesSourceIds, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) +void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas, + Storage::SynchronizationPackage &package) { - 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, qmltypesPath, imports, types, sourceIds, fileStatuses); + parseTypeInfo(projectData, qmltypesPath, package); } } -void ProjectUpdater::parseTypeInfo(SourceId sourceId, +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(sourceId, fileStatuses) == FileState::Changed) { - sourceIds.push_back(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, sourceIds); + 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) @@ -174,23 +154,23 @@ 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.moduleId = moduleId; type.accessSemantics = Storage::TypeAccessSemantics::Reference; type.sourceId = sourceId; type.exportedTypes.push_back( - Storage::ExportedType{Utils::SmallString{component.typeName}, + Storage::ExportedType{moduleId, + 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 dfe8ce05c44..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); - void parseTypeInfos(const SourceIds &qmltypesSourceIds, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); - void parseTypeInfo(SourceId sourceId, + Storage::SynchronizationPackage &package); + void parseTypeInfos(const Storage::ProjectDatas &projectDatas, + 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/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp new file mode 100644 index 00000000000..c4a2bae6178 --- /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, + QmlDocumentParser::ProjectStorage &storage) +{ + for (const QmlDom::Import &qmlImport : qmlImports) { + if (qmlImport.uri == u"file://.") { + auto moduleId = storage.moduleId(pathCache.sourceContextPath(sourceContextId)); + imports.emplace_back(moduleId, Storage::Version{}, sourceId); + } else if (qmlImport.uri.startsWith(u"file://")) { + auto moduleId = storage.moduleId(convertUri(qmlImport.uri)); + imports.emplace_back(moduleId, Storage::Version{}, sourceId); + } else { + auto moduleId = storage.moduleId(Utils::SmallString{qmlImport.uri}); + imports.emplace_back(moduleId, 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, m_storage); + + 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..e2dd2434058 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 ProjectStorage = QmlDesigner::ProjectStorage; + using PathCache = QmlDesigner::SourcePathCache; + + QmlDocumentParser(PathCache &pathCache, ProjectStorage &storage) + : m_pathCache{pathCache} + , m_storage{storage} + {} + + virtual Storage::Type parse(const QString &sourceContent, + Storage::Imports &imports, + SourceId sourceId, + SourceContextId sourceContextId); + +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 new file mode 100644 index 00000000000..f5d09409aa3 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** 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 appendImports(Storage::Imports &imports, + const QString &dependency, + SourceId sourceId, + QmlTypesParser::ProjectStorage &storage) +{ + auto spaceFound = std::find_if(dependency.begin(), dependency.end(), [](QChar c) { + return c.isSpace(); + }); + + Utils::PathString moduleName{QStringView(dependency.begin(), spaceFound)}; + moduleName.append("-cppnative"); + ModuleId cppModuleId = storage.moduleId(moduleName); + + 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(); + }); + + Storage::Version version; + + QStringView majorVersionString(majorVersionFound, majorVersionEnd); + 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()) + version.minor.value = QStringView(minorVersionFound, minorVersionEnd).toInt(); + } + + 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-cppnative"), Storage::Version{}, sourceId); +} + +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(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(storage.moduleId(Utils::SmallString{qmlExport.package()}), + Utils::SmallString{qmlExport.type()}, + createVersion(qmlExport.version())); + } + + exportedTypes.emplace_back(cppModuleId, Utils::SmallString{component.internalName()}); + + 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 cppModuleId, + const QQmlJSScope &component, + QmlTypesParser::ProjectStorage &storage) +{ + auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals(component.ownMethods()); + types.emplace_back(Utils::SmallString{component.internalName()}, + Storage::NativeType{Utils::SmallString{component.baseTypeName()}}, + createTypeAccessSemantics(component.accessSemantics()), + sourceId, + createExports(component.exports(), component, storage, cppModuleId), + createProperties(component.ownProperties()), + std::move(functionsDeclarations), + std::move(signalDeclarations), + createEnumeration(component.ownEnumerations())); +} + +void addTypes(Storage::Types &types, + const Storage::ProjectData &projectData, + const QHash &objects, + QmlTypesParser::ProjectStorage &storage) +{ + types.reserve(Utils::usize(objects) + types.size()); + + for (const auto &object : objects) + addType(types, projectData.sourceId, projectData.extraModuleId, *object.get(), storage); +} + +} // namespace + +void QmlTypesParser::parse(const QString &sourceContent, + Storage::Imports &imports, + Storage::Types &types, + const Storage::ProjectData &projectData) +{ + QQmlJSTypeDescriptionReader reader({}, sourceContent); + QHash components; + QStringList dependencies; + bool isValid = reader(&components, &dependencies); + if (!isValid) + throw CannotParseQmlTypesFile{}; + + 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 new file mode 100644 index 00000000000..40f88d240dc --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 "qmltypesparserinterface.h" + +namespace Sqlite { +class Database; +} + +namespace QmlDesigner { + +template +class ProjectStorage; + +template +class SourcePathCache; + +class QmlTypesParser : public QmlTypesParserInterface +{ +public: + using ProjectStorage = QmlDesigner::ProjectStorage; + using PathCache = QmlDesigner::SourcePathCache; + + QmlTypesParser(PathCache &pathCache, ProjectStorage &storage) + : m_pathCache{pathCache} + , m_storage{storage} + {} + + void parse(const QString &sourceContent, + Storage::Imports &imports, + Storage::Types &types, + const Storage::ProjectData &projectData) override; + +private: + PathCache &m_pathCache; + ProjectStorage &m_storage; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h index 40c98838353..3255c0b5aac 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h @@ -37,7 +37,7 @@ public: virtual void parse(const QString &sourceContent, Storage::Imports &imports, Storage::Types &types, - SourceIds &sourceIds) + const Storage::ProjectData &projectData) = 0; protected: diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp new file mode 100644 index 00000000000..8e96c0ec95e --- /dev/null +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** 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 +#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", 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 00000000000..9c7df42bc70 Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/component-icon.png differ 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 00000000000..99941541c6f Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/component-icon16.png differ 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 00000000000..f66349a63b2 Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/component-icon@2x.png differ 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 00000000000..29082eacf16 Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/loader-icon16.png b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon16.png new file mode 100644 index 00000000000..4a2b093259e Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon16.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/loader-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon@2x.png new file mode 100644 index 00000000000..750b13bd02d Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon@2x.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon.png new file mode 100644 index 00000000000..efe3ca80b46 Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon.png differ 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 00000000000..775a57a38c3 Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon16.png differ 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 00000000000..bb541b67112 Binary files /dev/null and b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon@2x.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc index be1770378b1..8adfb84baf2 100644 --- a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc +++ b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc @@ -72,5 +72,14 @@ images/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" } } 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: 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/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp index 53c76263a2f..962b4034925 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp @@ -99,6 +99,14 @@ 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 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 b7aa7ec434c..249474a224f 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp @@ -77,6 +77,18 @@ void QmlProjectItem::setFileSelectors(const QStringList &selectors) m_fileSelectors = selectors; } +void QmlProjectItem::setSupportedLanguages(const QStringList &languages) +{ + if (m_supportedLanguages != 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 2f0f8786ef7..90d17e48591 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h @@ -63,6 +63,12 @@ public: QStringList fileSelectors() const { return m_fileSelectors; } void setFileSelectors(const QStringList &selectors); + 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; @@ -85,6 +91,8 @@ protected: QString m_targetDirectory; 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 c1b8c6dc430..876fa4e1882 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -340,6 +340,20 @@ QStringList QmlBuildSystem::customFileSelectors() const return {}; } +QStringList QmlBuildSystem::supportedLanguages() const +{ + if (m_projectItem) + return m_projectItem.data()->supportedLanguages(); + return {}; +} + +QString QmlBuildSystem::primaryLanguage() const +{ + if (m_projectItem) + return m_projectItem.data()->primaryLanguage(); + return {}; +} + void QmlBuildSystem::refreshProjectFile() { refresh(QmlBuildSystem::ProjectFile | Files); @@ -509,6 +523,10 @@ QVariant QmlBuildSystem::additionalData(Id id) const { if (id == Constants::customFileSelectorsData) 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 51028b0d549..64c0cc90ecb 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -88,6 +88,8 @@ public: Utils::EnvironmentItems environment() const; 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 7a8df1f4f80..184469f2430 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectconstants.h +++ b/src/plugins/qmlprojectmanager/qmlprojectconstants.h @@ -32,6 +32,8 @@ 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"; 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/resourceeditor/resourceeditorplugin.cpp b/src/plugins/resourceeditor/resourceeditorplugin.cpp index 62a4d752456..36de99ca394 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,35 @@ 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); + }, {}, [](const FolderNode *fn) { + return dynamic_cast(fn) == nullptr; + }); + 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; 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; 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/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 52957d71925..d1195675624 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -342,10 +342,6 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro 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); connect(&m_removeSplashTimer, &QTimer::timeout, this, [this] { closeSplashScreen(); }); 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/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) { diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index d7643af772c..90d141808a5 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() @@ -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/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index d24b96dd5f8..c2f4d4a0c9c 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) @@ -983,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: { 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", 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 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 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 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 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") 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) {} + } + } + } } } 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/* 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..3123ffcf1d7 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) @@ -1080,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) @@ -1101,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 << ")"; } @@ -1112,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) @@ -1171,14 +1186,14 @@ std::ostream &operator<<(std::ostream &out, const EnumerationDeclaration &enumer << enumerationDeclaration.enumeratorDeclarations << ")"; } -std::ostream &operator<<(std::ostream &out, const Module &module) +std::ostream &operator<<(std::ostream &out, const ImportKind &importKind) { - return out << "(" << module.name << ", " << module.sourceId << ")"; + return out << importKindToText(importKind); } std::ostream &operator<<(std::ostream &out, const Import &import) { - return out << "(" << import.name << ", " << import.version << ", " << import.sourceId << ")"; + 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 d2c20d92b5f..074fada6d91 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -260,8 +260,7 @@ class ParameterDeclaration; class SignalDeclaration; class EnumerationDeclaration; class EnumeratorDeclaration; -class Module; -class ModuleDependency; +enum class ImportKind : char; class Import; enum class IsQualified : int; @@ -280,8 +279,7 @@ 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..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; @@ -83,34 +84,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 +107,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 +131,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: @@ -212,214 +203,209 @@ protected: storage.fetchSourceId(sourceContextId3, "bar"); } - auto createTypes() + auto createSimpleSynchronizationPackage() { - imports.emplace_back("Qml", Storage::Version{}, sourceId1); - imports.emplace_back("Qml", Storage::Version{}, sourceId2); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId1); + SynchronizationPackage package; - importsSourceId1.emplace_back("Qml", Storage::Version{}, sourceId1); - importsSourceId1.emplace_back("QtQuick", Storage::Version{}, sourceId1); + 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); - importsSourceId2.emplace_back("Qml", Storage::Version{}, sourceId2); + 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); - return Storage::Types{ - Storage::Type{ - qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Item"}}, - {Storage::PropertyDeclaration{"data", - Storage::NativeType{"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}}}}}, - Storage::Type{qmlModuleId, - "QObject", - Storage::NativeType{}, + importsSourceId2.emplace_back(qmlModuleId, Storage::Version{}, sourceId2); + importsSourceId2.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId2); + + 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{"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"}}}); + + package.sourceIds = {sourceId1, sourceId2}; + + return package; } - auto createVersionedTypes() + auto createSynchronizationPackageWithAliases() { - 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}}}}}; - } + 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"}; + package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4); + package.imports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); + package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId4); - return types; - } + 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); - auto createTypesWithAliases() - { - auto types = createTypes(); + importsSourceId4.emplace_back(qmlModuleId, Storage::Version{}, sourceId4); + importsSourceId4.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4); + importsSourceId4.emplace_back(pathToModuleId, Storage::Version{}, sourceId4); - imports.emplace_back("Qml", Storage::Version{}, sourceId3); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); - - imports.emplace_back("Qml", Storage::Version{}, sourceId4); - imports.emplace_back("/path/to", Storage::Version{}, sourceId4); - - importsSourceId3.emplace_back("Qml", Storage::Version{}, sourceId3); - importsSourceId3.emplace_back("QtQuick", Storage::Version{}, sourceId3); - - importsSourceId4.emplace_back("Qml", Storage::Version{}, sourceId4); - importsSourceId4.emplace_back("/path/to", Storage::Version{}, sourceId4); - - types[1].propertyDeclarations.push_back( + package.types[1].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QObject"}, + Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsList}); - - types.push_back(Storage::Type{qtQuickModuleId, - "QAliasItem", - Storage::ImportedType{"Item"}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"AliasItem"}}}); - 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::NativeType{"QObject"}, + 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{pathToModuleId, - "QObject2", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId4, - {Storage::ExportedType{"Object2"}, Storage::ExportedType{"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::NativeType{"QObject"}, + 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("Qml", Storage::Version{}, sourceId5); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId5); + auto package{createSynchronizationPackageWithAliases()}; - auto types = createTypesWithAliases(); - types.push_back(Storage::Type{qtQuickModuleId, - "QAliasItem2", - Storage::ImportedType{"Object"}, - TypeAccessSemantics::Reference, - sourceId5, - {Storage::ExportedType{"AliasItem2"}}}); + 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::NativeType{"QObject"}; - 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::Modules createModules() - { - return Storage::Modules{Storage::Module{"Qml", qmlModuleSourceId}, - Storage::Module{"QtQuick", qtQuickModuleSourceId}, - Storage::Module{"/path/to", pathToModuleSourceId}}; - } + package.sourceIds.push_back(sourceId1); - 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 package; } template @@ -428,9 +414,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}; @@ -439,27 +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)}; - Storage::Modules modules{createModules()}; - ModuleId qmlModuleId{&qmlModuleSourceId}; - ModuleId qtQuickModuleId{&qtQuickModuleSourceId}; - ModuleId pathToModuleId{&pathToModuleSourceId}; - Storage::Imports imports; + 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 importsSourceId1; Storage::Imports importsSourceId2; Storage::Imports importsSourceId3; @@ -671,1779 +651,1206 @@ TEST_F(ProjectStorage, FetchSourceIdUnguardedWithNonExistingSourceContextIdThrow TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypes) { - Storage::Types types{createTypes()}; + auto package{createSimpleSynchronizationPackage()}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(std::move(package)); - 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) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::ImportedType{"Object"}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::ImportedType{"Object"}; - storage.synchronize( - modules, - importsSourceId1, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(std::move(package)); - 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) { - Storage::Types types{createTypes()}; - types[0].prototype = Storage::ImportedType{"Objec"}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::ImportedType{"Objec"}; - ASSERT_THROW(storage.synchronize(modules, - imports, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); -} - -TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithMissingModuleAndPrototypeName) -{ - Storage::Types types{createTypes()}; - types.push_back(Storage::Type{pathToModuleId, - "QObject2", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object2"}, Storage::ExportedType{"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}, {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(std::move(package)), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithMissingModule) { - Storage::Types types{createTypes()}; - storage.synchronize(modules, - imports, - {}, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + 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({}, - imports, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::ModuleDoesNotExists); + 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(std::move(package)); - 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}, - {}); - 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(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}, - {}); - 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("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(SynchronizationPackage{newImports, + package.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()}; + 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].prototype = Storage::NativeType{"QQuickObject"}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Object"}}}); + SynchronizationPackage{importsSourceId1, {package.types[0], package.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::Version{}, - sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Object"}}}); + 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); - 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"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Item"}}}}; + 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( - modules, - 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{ModuleId{}, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"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{qtQuickModuleId, - "QQuickItem", - Storage::NativeType{""}, - TypeAccessSemantics::Reference, - SourceId{}, - {Storage::ExportedType{"Item"}}}}; + auto package{createSimpleSynchronizationPackage()}; + package.types = {Storage::Type{"QQuickItem", + Storage::ImportedType{""}, + TypeAccessSemantics::Reference, + SourceId{}, + {Storage::ExportedType{qtQuickModuleId, "Item"}}}}; - ASSERT_THROW(storage.synchronize( - modules, - 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( - modules, - 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(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(); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); - storage.synchronize({}, importsSourceId1, types, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.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, - "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"; + 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(), - 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(); + 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); 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)))))); } -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(modules, - {}, - types, - {sourceId1, - sourceId2, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}), - QmlDesigner::TypeNameDoesNotExists); -} - -TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationsWithMissingImportsForExportedTypes) -{ - 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}, {}), - QmlDesigner::TypeNameDoesNotExists); + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } 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"}, - TypeAccessSemantics::Reference, - sourceId1, - {Storage::ExportedType{"Object"}}}); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = 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.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); 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)))))); } 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"}; + 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(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)))))); } 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; + 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( - 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)))))); } 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"}; + 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( - 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)))))); } TEST_F(ProjectStorage, SynchronizeTypesRemovesAPropertyDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - modules, - 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(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)))))); } TEST_F(ProjectStorage, SynchronizeTypesAddsAPropertyDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - modules, - 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::NativeType{"QObject"}, + Storage::ImportedType{"QObject"}, Storage::PropertyDeclarationTraits::IsPointer}); - storage.synchronize({}, importsSourceId1, {types[0]}, {sourceId1}, {}); + storage.synchronize(SynchronizationPackage{importsSourceId1, {package.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)))))); } TEST_F(ProjectStorage, SynchronizeTypesRenameAPropertyDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - modules, - 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( - 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)))))); } -TEST_F(ProjectStorage, UsingNonExistingNativePropertyTypeThrows) +TEST_F(ProjectStorage, UsingNonExistingPropertyTypeThrows) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::NativeType{"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(modules, - 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(modules, - 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{ - "QObject2", Storage::Import{"Qml", Storage::Version{}, sourceId1}}; - types.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + "QObject2", Storage::Import{qmlNativeModuleId, Storage::Version{}, sourceId1}}; + package.types.pop_back(); + package.imports = importsSourceId1; - ASSERT_THROW(storage.synchronize(modules, - 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{ - "QObject", Storage::Import{"QtQuick", Storage::Version{}, sourceId1}}; - types.pop_back(); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + "QObject", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; + package.types.pop_back(); + package.imports = importsSourceId1; - ASSERT_THROW(storage.synchronize(modules, - 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[0].prototype = Storage::NativeType{}; - 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(modules, - 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf(IsStorageType(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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( - modules, - 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(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])))))); + UnorderedElementsAre( + Eq(package.types[0].enumerationDeclarations[0])))))); } TEST_F(ProjectStorage, SynchronizeTypesAddEnumerationDeclaration) { - Storage::Types types{createTypes()}; - storage.synchronize( - modules, - 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(qtQuickModuleId, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - 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, SynchronizeModulesAddModules) +TEST_F(ProjectStorage, FetchTypeIdBySourceIdAndName) { - Storage::Modules modules{createModules()}; + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); - 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) -{ - 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)); } TEST_F(ProjectStorage, FetchTypeIdByExportedName) { - Storage::Types types{createTypes()}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - auto qmlModuleId = storage.fetchModuleId("Qml"); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); 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 package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); 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 package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({}, "Object"); ASSERT_FALSE(typeId.isValid()); @@ -2451,13 +1858,9 @@ TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAre TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAreInvalid) { - Storage::Types types{createTypes()}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({ModuleId{}}, "Object"); ASSERT_FALSE(typeId.isValid()); @@ -2465,14 +1868,10 @@ TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfModuleIdsAre TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfNotInModule) { - Storage::Types types{createTypes()}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - auto qtQuickModuleId = storage.fetchModuleId("QtQuick"); + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + auto qtQuickModuleId = storage.moduleId("QtQuick"); + auto typeId = storage.fetchTypeIdByModuleIdsAndExportedName({qtQuickModuleId}, "Object"); ASSERT_FALSE(typeId.isValid()); @@ -2480,1283 +1879,906 @@ TEST_F(ProjectStorage, FetchInvalidTypeIdByImporIdsAndExportedNameIfNotInModule) TEST_F(ProjectStorage, SynchronizeTypesAddAliasDeclarations) { - Storage::Types types{createTypesWithAliases()}; + auto package{createSynchronizationPackageWithAliases()}; - storage.synchronize(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); 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, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + auto package{createSynchronizationPackageWithAliases()}; + storage.synchronize(package); - storage.synchronize(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); 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, - 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( - 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"}; + auto package{createSynchronizationPackageWithAliases()}; + package.types[2].propertyDeclarations[1].typeName = Storage::ImportedType{"QQuickItemWrong"}; - ASSERT_THROW(storage.synchronize(modules, 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(modules, 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(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Obj2"}; - importsSourceId3.emplace_back("/path/to", Storage::Version{}, sourceId3); + 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( - 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, - 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(), 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, - 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::NativeType{"QQuickItem"}, + 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(), 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, 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::NativeType{"QQuickItem"}, + Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(modules, - 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( - 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, - 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(), 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, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Item"}; - importsSourceId2.emplace_back("QtQuick", Storage::Version{}, sourceId2); + 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( - 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, - 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(modules, - 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( - 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, SynchronizeTypesRemoveTypeWithAliasTargetPropertyDeclarationThrows) { - Storage::Types types{createTypesWithAliases()}; - types[2].propertyDeclarations[2].typeName = Storage::ImportedType{"Object2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId3); - storage.synchronize(modules, - 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("/path/to", Storage::Version{}, sourceId3); - storage.synchronize(modules, - 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( - 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, - 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::NativeType{"QQuickItem"}, + 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(), 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, AliasPropertyIsOverloaded) { - Storage::Types types{createTypesWithAliases()}; - types[0].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithAliases()}; + package.types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QQuickItem"}, + Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); 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, UpdateAliasPropertyIfOverloadedPropertyIsRemoved) { - Storage::Types types{createTypesWithAliases()}; - types[0].propertyDeclarations.push_back( + auto package{createSynchronizationPackageWithAliases()}; + package.types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"objects", - Storage::NativeType{"QQuickItem"}, + Storage::ImportedType{"QQuickItem"}, Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsReadOnly}); - storage.synchronize(modules, - 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( - 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, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].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( - 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)))))); } 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, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].moduleId = qtQuickModuleId; - importsSourceId4.emplace_back("QtQuick", Storage::Version{}, sourceId4); + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + "Object2", Storage::Import{pathToModuleId, Storage::Version{}, sourceId2}}; + 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{ - "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{}, - TypeAccessSemantics::Reference, - sourceId5, - {Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}}); + auto package{createSynchronizationPackageWithAliases()}; + package.types[1].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + "Object2", Storage::Import{pathToModuleId, Storage::Version{}, sourceId2}}; + 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(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); 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)))))); } 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(modules, - 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( - 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); + 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(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].moduleId = qtQuickModuleId; - - storage.synchronize({}, importsSourceId4, {types[3]}, {sourceId3, sourceId4}, {}); + storage.synchronize( + SynchronizationPackage{importsSourceId4, {package.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, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[0].prototype = Storage::NativeType{}; - importsSourceId1.emplace_back("/path/to", Storage::Version{}, sourceId1); - importsSourceId4.emplace_back("QtQuick", Storage::Version{}, sourceId4); - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - types[3].propertyDeclarations[0].typeName = Storage::ImportedType{"Item"}; + 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); + 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::NativeType{"QObject2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - storage.synchronize(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].moduleId = qtQuickModuleId; - types[1].propertyDeclarations[0].typeName = Storage::NativeType{"QObject"}; - importsSourceId4.emplace_back("QtQuick", Storage::Version{}, sourceId4); + 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(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, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types.pop_back(); + 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::NativeType{"QObject2"}; - imports.emplace_back("/path/to", Storage::Version{}, sourceId2); - storage.synchronize(modules, - 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( - modules, - 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(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; + 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(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::Version{}, - sourceId1}}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].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{"Qml", - Storage::Version{}, - sourceId1}}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].moduleId = qtQuickModuleId; - types[0].prototype = Storage::QualifiedImportedType{"Object", - Storage::Import{"QtQuick", - 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(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].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(qtQuickModuleId, + Contains(IsStorageType(sourceId1, "QQuickItem", - Storage::NativeType{"QObject3"}, - TypeAccessSemantics::Reference, - sourceId1))); + fetchTypeId(sourceId2, "QObject3"), + TypeAccessSemantics::Reference))); } TEST_F(ProjectStorage, ChangePrototypeTypeNameThrowsForWrongNativePrototupeTypeName) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::ImportedType{"Object"}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - 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{pathToModuleId, - "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); + 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(modules, - 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(modules, - 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( - 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); + 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(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); + storage.synchronize(package); 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, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - sourceId5, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[1].propertyDeclarations[0].typeName = Storage::ImportedType{"Object2"}; - importsSourceId2.emplace_back("/path/to", Storage::Version{}, sourceId2); + 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(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, - 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(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)))))); } TEST_F(ProjectStorage, UpdateAliasesAfterChangeAliasToProperty) { - Storage::Types types{createTypesWithRecursiveAliases()}; - storage.synchronize(modules, - 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(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, ""))))))); @@ -3764,38 +2786,26 @@ 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(modules, - 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("/path/to", Storage::Version{}, sourceId2); + 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(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")))))); @@ -3803,379 +2813,270 @@ 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("QtQuick", Storage::Version{}, sourceId2); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2); - ASSERT_THROW(storage.synchronize(modules, - 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(modules, - 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("QtQuick", Storage::Version{}, sourceId2); + 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{"Qml", - Storage::Version{}, - sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", 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( - modules, - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); 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::Version{}, - sourceId1}}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qtQuickModuleId, + Storage::Version{}, + sourceId1}}; - ASSERT_THROW(storage.synchronize(modules, - 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{"QtQuick", - Storage::Version{}, - sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", 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( - modules, - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); 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::Version{4}, - sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", 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(modules, - 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{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", 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( - modules, - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); 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) { - 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(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object", Storage::Version{2}}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + 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}}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3); + package.sourceIds.push_back(sourceId3); - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); 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::Version{2}, - sourceId1}}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::QualifiedImportedType{"Object", + Storage::Import{qtQuickModuleId, + Storage::Version{2}, + sourceId1}}; - ASSERT_THROW(storage.synchronize(modules, - 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{ - "Object", Storage::Import{"Qml", Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = 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( - modules, - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains( Field(&Storage::Type::propertyDeclarations, Contains(IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList))))); } TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameDownTheModuleChainThrows) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"QtQuick", Storage::Version{}, sourceId1}}; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; - ASSERT_THROW(storage.synchronize(modules, - 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{ - "Object", Storage::Import{"QtQuick", Storage::Version{}, sourceId1}}; - types.push_back(Storage::Type{qtQuickModuleId, - "QQuickObject", - Storage::NativeType{}, - TypeAccessSemantics::Reference, - sourceId3, - {Storage::ExportedType{"Object"}}}); - imports.emplace_back("QtQuick", Storage::Version{}, sourceId3); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = 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( - modules, - imports, - types, - {sourceId1, sourceId2, sourceId3, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains( Field(&Storage::Type::propertyDeclarations, Contains(IsPropertyDeclaration("data", - Storage::NativeType{"QQuickObject"}, + fetchTypeId(sourceId3, "QQuickObject"), Storage::PropertyDeclarationTraits::IsList))))); } 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); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + "Object", Storage::Import{qmlModuleId, Storage::Version{2}, sourceId1}}; + package.imports.emplace_back(qmlModuleId, Storage::Version{2}, sourceId1); - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + storage.synchronize(package); ASSERT_THAT(storage.fetchTypes(), Contains( Field(&Storage::Type::propertyDeclarations, Contains(IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, + fetchTypeId(sourceId2, "QObject"), Storage::PropertyDeclarationTraits::IsList))))); } TEST_F(ProjectStorage, ChangePropertyTypeModuleIdWithQualifiedTypeThrows) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"Qml", Storage::Version{}, sourceId1}}; - storage.synchronize( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - types[1].moduleId = qtQuickModuleId; + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = 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, ChangePropertyTypeModuleIdWithQualifiedType) { - Storage::Types types{createTypes()}; - types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ - "Object", Storage::Import{"Qml", 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); + auto package{createSimpleSynchronizationPackage()}; + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + "Object", Storage::Import{qmlModuleId, Storage::Version{}, sourceId1}}; + storage.synchronize(package); + package.types[0].propertyDeclarations[0].typeName = Storage::QualifiedImportedType{ + "Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}}; + 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(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 +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)); @@ -4194,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)); } @@ -4206,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)); @@ -4218,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); } @@ -4226,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()); @@ -4237,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()); @@ -4248,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); @@ -4257,30 +3158,18 @@ TEST_F(ProjectStorage, FetchFileStatus) TEST_F(ProjectStorage, SynchronizeTypesWithoutTypeName) { - Storage::Types types{createTypesWithAliases()}; - storage.synchronize(modules, - imports, - types, - {sourceId1, - sourceId2, - sourceId3, - sourceId4, - qmlModuleSourceId, - qtQuickModuleSourceId, - pathToModuleSourceId}, - {}); - types[3].typeName.clear(); - types[3].moduleId = ModuleId{}; - 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(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")))))); @@ -4288,563 +3177,481 @@ TEST_F(ProjectStorage, SynchronizeTypesWithoutTypeName) TEST_F(ProjectStorage, FetchByMajorVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{1}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{1, 2}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedTypeIfMinorVersionIsNotExportedThrows) { - auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{1, 1}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchLowMinorVersionForImportedTypeThrows) { - auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchLowMinorVersionForQualifiedImportedTypeThrows) { - auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{1, 1}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchHigherMinorVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{1, 3}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchDifferentMajorVersionForQualifiedImportedTypeThrows) { - auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{3, 1}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{import}, {type}, {sourceId2}}), QmlDesigner::TypeNameDoesNotExists); } TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForImportedType) { - auto types = createVersionedTypes(); - storage.synchronize(modules, - imports, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{2, 3}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{2}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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, - types, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Import import{"Qml", Storage::Version{}, sourceId2}; - Storage::Type type{qtQuickModuleId, - "Item", + auto package{createSynchronizationPackageWithVersions()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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}, - {type}, - {sourceId1, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); + Storage::Import import{qmlModuleId, Storage::Version{}, sourceId1}; + 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( - modules, - 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( - modules, - imports, - types, - {sourceId1, sourceId2, qmlModuleSourceId, qtQuickModuleSourceId, pathToModuleSourceId}, - {}); - Storage::Type quickType{qtQuickModuleId, - "QQuickItem", + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + 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(SynchronizationPackage{{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..42de0b0b40a 100644 --- a/tests/unit/unittest/projectstoragemock.h +++ b/tests/unit/unittest/projectstoragemock.h @@ -36,22 +36,17 @@ class ProjectStorageMock : public QmlDesigner::ProjectStorageInterface { public: - MOCK_METHOD(void, - synchronize, - (QmlDesigner::Storage::Modules modules, - 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)); MOCK_METHOD(QmlDesigner::FileStatus, fetchFileStatus, (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 d198587821e..c26aaa7b70a 100644 --- a/tests/unit/unittest/projectstorageupdater-test.cpp +++ b/tests/unit/unittest/projectstorageupdater-test.cpp @@ -42,26 +42,26 @@ 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::SynchronizationPackage; 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 +78,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, @@ -114,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: @@ -134,8 +135,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"})); @@ -154,6 +157,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 +208,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 +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(), IsEmpty())); + EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); updater.update(); } @@ -330,23 +335,26 @@ 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)); ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)) - .WillByDefault([&](auto, auto &imports, auto &types, auto &sourceIds) { + .WillByDefault([&](auto, auto &imports, auto &types, auto) { types.push_back(objectType); imports.push_back(import); }); + EXPECT_CALL(projectStorageMock, moduleId(Eq("Example"))); EXPECT_CALL(projectStorageMock, - synchronize(ElementsAre(IsModule("Example", qmlDirPathSourceId)), - 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(); } @@ -357,9 +365,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged) 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); - }); + .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))) @@ -367,8 +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(), IsEmpty())); + EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); updater.update(); } @@ -415,39 +420,40 @@ 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(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(); } @@ -462,51 +468,28 @@ 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))))), - UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2), - UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421), - IsFileStatus(qmlDocumentSourceId1, 22, 12), - IsFileStatus(qmlDocumentSourceId2, 22, 13)))); - - 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)))); + 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(); } diff --git a/tests/unit/unittest/qmldocumentparser-test.cpp b/tests/unit/unittest/qmldocumentparser-test.cpp new file mode 100644 index 00000000000..451003ba33c --- /dev/null +++ b/tests/unit/unittest/qmldocumentparser-test.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** 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}; + 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 exampleModuleId = storage.moduleId("Example"); + auto type = parser.parse("import Example as Example\n Example.Item{}", + imports, + qmlFileSourceId, + qmlFileSourceContextId); + + ASSERT_THAT(type, + HasPrototype(Storage::QualifiedImportedType( + "Item", Storage::Import{exampleModuleId, 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 = 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, + qmlFileSourceContextId); + + ASSERT_THAT(imports, + UnorderedElementsAre( + 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) +{ + 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..9de60a1807f --- /dev/null +++ b/tests/unit/unittest/qmltypesparser-test.cpp @@ -0,0 +1,397 @@ +/**************************************************************************** +** +** 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_P3(IsImport, + moduleId, + version, + sourceId, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::Import{moduleId, version, sourceId})) +{ + const Storage::Import &import = arg; + + return import.moduleId == moduleId && import.version == version && import.sourceId == 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_P4(IsType, + typeName, + prototype, + accessSemantics, + sourceId, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::Type{typeName, prototype, accessSemantics, sourceId})) +{ + const Storage::Type &type = arg; + + return 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}; + 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/")}; +}; + +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, projectData); + + ASSERT_THAT( + imports, + UnorderedElementsAre( + IsImport(storage.moduleId("QML"), Storage::Version{}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQml-cppnative"), Storage::Version{}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQuick-cppnative"), Storage::Version{2, 15}, qmltypesFileSourceId), + IsImport(storage.moduleId("QtQuick.Window-cppnative"), + Storage::Version{2, 1}, + qmltypesFileSourceId), + IsImport(storage.moduleId("QtFoo-cppnative"), Storage::Version{6}, qmltypesFileSourceId))); +} + +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, projectData); + + ASSERT_THAT(types, + UnorderedElementsAre(IsType("QObject", + Storage::NativeType{}, + Storage::TypeAccessSemantics::Reference, + qmltypesFileSourceId), + IsType("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: ["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, projectData); + + 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) +{ + 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, projectData); + + 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, projectData); + + 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, projectData); + + 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, projectData); + + 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..6cf52713797 100644 --- a/tests/unit/unittest/qmltypesparsermock.h +++ b/tests/unit/unittest/qmltypesparsermock.h @@ -37,6 +37,6 @@ public: (const QString &sourceContent, QmlDesigner::Storage::Imports &imports, QmlDesigner::Storage::Types &types, - QmlDesigner::SourceIds &sourceIds), + const QmlDesigner::Storage::ProjectData &projectData), (override)); };