- Qt 6.9
- Qt QML Compiler
- QML Static Analysis Tutorial
- QML Static Analysis 1 - Basic Setup
- Qt 6.9.3 Reference Documentation

QML Static Analysis Tutorial ◦ Custom Pass

# QML Static Analysis 1 - Basic Setup

This chapter introduces the basic structure of a qmllint extension plugin, and how it can be used with qmllint.

To create our plugin, we first need to make the QmlCompiler module available:

     find_package(Qt6 REQUIRED COMPONENTS QmlCompiler)

We then create a plugin, and link it against the QmlCompiler module.

     qt_add_plugin(HelloWorldPlugin)

     target_sources(HelloWorldPlugin
         PRIVATE
             helloplugin.h
             helloplugin.cpp
     )

     target_link_libraries(HelloWorldPlugin PRIVATE Qt::QmlCompiler)

The implementation follows the pattern for extending Qt with a plugin: We subclass the QQmlSA::LintPlugin,

     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;
     };

The plugin references a `plugin.json` file, which contains some important information:

     {
         "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"
             }
         ]
     }

`name`, `author`, `version` and `description` are meta-data to describe the plugin.

Each plugin can have one or more logging categories, which are used to thematically group warnings. `loggingCategories` takes an array of categories, each consisting of

- `name`, which is used to identify the category, and as the flag name in qmllint,
- `settingsName`, which is used to configure the category in qmllint.ini
- `description`, which should describe what kind of warning messages are tagged with the category

In our example, we have only one logging category, `hello-world`. For each category, we have to create a LoggerWarningId object in our plugin.

     static constexpr QQmlSA::LoggerWarningId helloWorld { "Plugin.HelloWorld.hello-world" };

We construct it with a string literal which should have the format `Plugin.<plugin name>.<category name>`.

Lastly, for our plugin to actually do anything useful, we have to implement the `registerPasses` function.

     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
     }

We check whether our category is enabled, and print a diagnostic indicating its status via qDebug. Note that the plugin currently does not do anything useful, as we do not register any passes. This will done in the next part of this tutorial.

We can however already verify that our plugin is correctly detected. We use the following command to check it:

     qmllint -P /path/to/the/directory/containing/the/plugin --Plugin.HelloWorld.hello-world info test.qml

The `-P` options tells qmllint to look for plugins in the specified folder. To avoid conflicts with Qt internal categories, plugin categories are always prefixed with "Plugin", then followed by a dot, the plugin name, another dot and finally the category. Running the command should print `Hello World Plugin is enabled`.