diff options
| author | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-09-01 17:57:19 +0200 |
|---|---|---|
| committer | Olivier De Cannière <olivier.decanniere@qt.io> | 2023-11-28 09:45:24 +0100 |
| commit | f4c13d1b738d25c563d00c0bc25e720775d985a3 (patch) | |
| tree | 8fa5485d45b05c5b7201215abf391266ed357de6 /examples/qmlcompiler/tutorials/helloworld | |
| parent | f8b6cdf63400103a6ca53c19bb845577e94b41be (diff) | |
QQmlSA: Add initial fixit section
FixSuggestion unfortunately still lacks class documentation, and we
probably need to rework the API before moving the module out of TP.
However, we should still show the basic usage of the module, including
fixit suggestions. Consequently, add a small example on how to write
FixSuggestions, and add a warning note that they should only be marked
as auto-applicable if the resulting code is still valid.
Pick-to: 6.6
Change-Id: I260021163e3afe2cda97fd82a9bf4e9c26a910e2
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'examples/qmlcompiler/tutorials/helloworld')
5 files changed, 146 insertions, 0 deletions
diff --git a/examples/qmlcompiler/tutorials/helloworld/chapter3/CMakeLists.txt b/examples/qmlcompiler/tutorials/helloworld/chapter3/CMakeLists.txt new file mode 100644 index 0000000000..b9466b61b3 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter3/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.21) + +project(hello_world_plugin VERSION 1.0.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS QmlCompiler) + +qt_standard_project_setup( + REQUIRES 6.6 +) + +qt_add_plugin(HelloWorldPlugin) + +target_sources(HelloWorldPlugin + PRIVATE + helloplugin.h + helloplugin.cpp +) + +target_link_libraries(HelloWorldPlugin PRIVATE Qt::QmlCompiler) diff --git a/examples/qmlcompiler/tutorials/helloworld/chapter3/helloplugin.cpp b/examples/qmlcompiler/tutorials/helloworld/chapter3/helloplugin.cpp new file mode 100644 index 0000000000..93ee6d80c4 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter3/helloplugin.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "helloplugin.h" +#include <QDebug> + +using namespace Qt::StringLiterals; + +static constexpr QQmlSA::LoggerWarningId helloWorld { "Plugin.HelloWorld.hello-world" }; + +class HelloWorldElementPass : public QQmlSA::ElementPass +{ +public: + HelloWorldElementPass(QQmlSA::PassManager *manager); + bool shouldRun(const QQmlSA::Element &element) override; + void run(const QQmlSA::Element &element) override; +private: + QQmlSA::Element m_textType; +}; + +HelloWorldElementPass::HelloWorldElementPass(QQmlSA::PassManager *manager) + : QQmlSA::ElementPass(manager) +{ + m_textType = resolveType("QtQuick", "Text"); +} + +bool HelloWorldElementPass::shouldRun(const QQmlSA::Element &element) +{ + if (!element.inherits(m_textType)) + return false; + if (!element.hasOwnPropertyBindings(u"text"_s)) + return false; + return true; +} + +void HelloWorldElementPass::run(const QQmlSA::Element &element) +{ + auto textBindings = element.ownPropertyBindings(u"text"_s); + for (const auto &textBinding: textBindings) { + if (textBinding.bindingType() != QQmlSA::BindingType::StringLiteral) + continue; + QString currentBinding = textBinding.stringValue(); + if (currentBinding == u"Hello world!"_s) + continue; + if (currentBinding == u"Goodbye world!"_s) { + QQmlSA::FixSuggestion suggestion(u"Replace 'Goodbye' with 'Hello'"_s, + textBinding.sourceLocation(), u"\"Hello world!\""_s); + suggestion.setAutoApplicable(true); + emitWarning("Incorrect greeting", helloWorld, textBinding.sourceLocation(), suggestion); + } + } +} + + +void HelloWorldPlugin::registerPasses(QQmlSA::PassManager *manager, const QQmlSA::Element &rootElement) +{ + const bool pluginIsEnabled = manager->isCategoryEnabled(helloWorld); + qDebug() << "Hello World plugin is" << (pluginIsEnabled ? "enabled" : "disabled"); + if (!pluginIsEnabled) + return; // skip registration if the plugin is disabled anyway + manager->registerElementPass(std::make_unique<HelloWorldElementPass>(manager)); +} + +#include "moc_helloplugin.cpp" diff --git a/examples/qmlcompiler/tutorials/helloworld/chapter3/helloplugin.h b/examples/qmlcompiler/tutorials/helloworld/chapter3/helloplugin.h new file mode 100644 index 0000000000..6666c78be0 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter3/helloplugin.h @@ -0,0 +1,21 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef HELLO_PLUGIN_H +#define HELLO_PLUGIN_H + +#include <QtCore/qobject.h> +#include <QtQmlCompiler/qqmlsa.h> + +class HelloWorldPlugin : public QObject, public QQmlSA::LintPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QmlLintPluginInterface_iid FILE "plugin.json") + Q_INTERFACES(QQmlSA::LintPlugin) + +public: + void registerPasses(QQmlSA::PassManager *manager, const QQmlSA::Element &rootElement) override; +}; + +#endif + diff --git a/examples/qmlcompiler/tutorials/helloworld/chapter3/plugin.json b/examples/qmlcompiler/tutorials/helloworld/chapter3/plugin.json new file mode 100644 index 0000000000..3d8c1ff206 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter3/plugin.json @@ -0,0 +1,13 @@ +{ + "name": "HelloWorld", + "author": "Qt Example", + "description": "Demonstrates how to write a qmllint plugin", + "version": "1.0", + "loggingCategories": [ + { + "name": "hello-world", + "settingsName": "HelloWorld", + "description": "Used to create test messages" + } + ] +} diff --git a/examples/qmlcompiler/tutorials/helloworld/chapter3/test.qml b/examples/qmlcompiler/tutorials/helloworld/chapter3/test.qml new file mode 100644 index 0000000000..42fbaa108f --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter3/test.qml @@ -0,0 +1,26 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +// [0] +import QtQuick + +Item { + id: root + + property string greeting: "Hello" + + component MyText : Text {} + + component NotText : Item { + property string text + } + + Text { text: "Hello world!" } + Text { text: root.greeting } + Text { text: "Goodbye world!" } + NotText { + text: "Does not trigger" + MyText { text: "Goodbye world!" } + } +} +// [0] |
