diff options
| author | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-08-29 16:49:53 +0200 |
|---|---|---|
| committer | Olivier De Cannière <olivier.decanniere@qt.io> | 2023-11-24 18:34:02 +0100 |
| commit | 7d991d78d210eebe5ed81d37dfd27106c77a6868 (patch) | |
| tree | a0dc99941d8cabfd838afc94c60ab3a49172a3ca /examples/qmlcompiler/tutorials/helloworld | |
| parent | dfb67989d1aac7a34f07288aa419680382cfff8f (diff) | |
QQmlSa: Start custom qmllint plugin tutorial
Pick-to: 6.6
Change-Id: I34e692f46c752a52ee42669c5431f4d546009e65
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Vladimir Minenko <vladimir.minenko@qt.io>
Diffstat (limited to 'examples/qmlcompiler/tutorials/helloworld')
10 files changed, 235 insertions, 0 deletions
diff --git a/examples/qmlcompiler/tutorials/helloworld/chapter1/CMakeLists.txt b/examples/qmlcompiler/tutorials/helloworld/chapter1/CMakeLists.txt new file mode 100644 index 0000000000..b9466b61b3 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter1/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/chapter1/helloplugin.cpp b/examples/qmlcompiler/tutorials/helloworld/chapter1/helloplugin.cpp new file mode 100644 index 0000000000..ad36e64fae --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter1/helloplugin.cpp @@ -0,0 +1,19 @@ +// 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" }; + +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 + // here we will later register our passes +} + +#include "moc_helloplugin.cpp" diff --git a/examples/qmlcompiler/tutorials/helloworld/chapter1/helloplugin.h b/examples/qmlcompiler/tutorials/helloworld/chapter1/helloplugin.h new file mode 100644 index 0000000000..6666c78be0 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter1/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/chapter1/plugin.json b/examples/qmlcompiler/tutorials/helloworld/chapter1/plugin.json new file mode 100644 index 0000000000..3d8c1ff206 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter1/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/chapter1/test.qml b/examples/qmlcompiler/tutorials/helloworld/chapter1/test.qml new file mode 100644 index 0000000000..99af71ad7d --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter1/test.qml @@ -0,0 +1,24 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +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!" } + } +} diff --git a/examples/qmlcompiler/tutorials/helloworld/chapter2/CMakeLists.txt b/examples/qmlcompiler/tutorials/helloworld/chapter2/CMakeLists.txt new file mode 100644 index 0000000000..b9466b61b3 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter2/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/chapter2/helloplugin.cpp b/examples/qmlcompiler/tutorials/helloworld/chapter2/helloplugin.cpp new file mode 100644 index 0000000000..431ad97f16 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter2/helloplugin.cpp @@ -0,0 +1,56 @@ +// 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; + if (textBinding.stringValue() != u"Hello world!"_s) + emitWarning("Incorrect greeting", helloWorld, textBinding.sourceLocation()); + } +} + +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/chapter2/helloplugin.h b/examples/qmlcompiler/tutorials/helloworld/chapter2/helloplugin.h new file mode 100644 index 0000000000..6666c78be0 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter2/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/chapter2/plugin.json b/examples/qmlcompiler/tutorials/helloworld/chapter2/plugin.json new file mode 100644 index 0000000000..3d8c1ff206 --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter2/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/chapter2/test.qml b/examples/qmlcompiler/tutorials/helloworld/chapter2/test.qml new file mode 100644 index 0000000000..99af71ad7d --- /dev/null +++ b/examples/qmlcompiler/tutorials/helloworld/chapter2/test.qml @@ -0,0 +1,24 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +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!" } + } +} |
