What's new in QML Tooling in Qt 6.2?

(By Fawzi Mohamed and Maximilian Goldstein)

Among several areas where we've made major strides, QML Tooling is one of the fastest advancing ones with a ton of new features added since Qt 5.15. Here we will be showing off progress and future plans in the fields of static analysis and formatting QML.

qmllint

qmllint has evolved a lot since its introduction in Qt 5.4. It started as a simple syntax checker. Since then it has gained the ability to warn about unqualified access, "with" statements and signal injection as well as various other best practice violations. Apart from greatly improved performance, here are only some of the new features in qmllint:

CMake qmllint target

With Qt 6.2 if you're using the new QML Module CMake API, you will always have a ${TARGETNAME}_qmllint target for your module. This means you can invoke qmllint without ever having to worry about import paths or linting all files since this will all be automatically taken care by the target.

More details about the QML Module API will be provided in a series of blog posts over the next weeks.

Deprecation warnings

You can now mark components and properties as deprecated, something which has existed in C++ for a long time:

import QtQuick
Text {
    @Deprecated { reason: "Use newProperty instead!" }
    property int oldProperty
    property int newProperty
    Component.onCompleted: console.log(oldProperty);  // Warning: XY.qml:8:40: Property "oldProperty" is deprecated (Reason: Use newProperty instead!)
}

This will make it easier to communicate about changes in your public API.

Toggling warnings via categories

You may now disable warnings on a per category basis, for example by default qmllint will inform you about unused imports:

import QtQuick
import QtQuick3D // Info: DEM.qml:2:1: Unused import at DEM.qml:2:1
Text {
    id: textElement
    text: "Hello world!"
    anchors.centerIn: parent
}

 

If you wish, you can now either suppress this information by passing --unused-imports disable. Or you can turn this informational message into a full blown warning by using --unused-imports warning. In that case, as with all warnings, the unused import warning will make qmllint return an exit code of 1 ; that will cause failure in any CI or pre-commit hooks that use the tool. See the output of qmllint --help for the complete list of warning categories.

Configuring qmllint via settings files

In addition to being able to provide options via the command line qmllint can now also be configured using settings files. These work similar to other linter configuration files.

See the documentation for more details.

This is especially useful to make your project ready for use in CI.

Disabling warnings via comments

Sometimes you may not be able to fix a warning immediately but find it useful in other places. For this reason we allow you to disable warnings on a per-line basis:

import QtQuick
Item {
   width: 50
   // This is an unqualified access
   height: appWindow.height // qmllint disable unqualified
   // ...
}

 

Learn more about disabling warnings via comments here.

Continuous Integration and Pre-Commit Hooks

qmllint can also be passed the --json option which will make the tool output its warnings in a machine readable format which is very useful for integration in CI and pre-commit hooks. For example, here is an application where qmllint's output is used to generate automatic code reviews on GitHub:image-Sep-03-2021-01-35-47-54-PM

Future plans

Even now work on qmllint is still ongoing and qmllint is going to feature greatly improved type checking and even more warning categories in Qt 6.3. We also plan to make qmllint more extendable so users are able to generate their own warnings tailored around their projects' specific needs.

qmlformat

We use QML to create beautiful GUIs, and QML can express what we want in a beautiful and concise way. The IDE/Editor (Qt Creator for example) can help us to keep all code indented to be more pleasing to read, and look at. Sometimes though one wants to just reformat it from the command line, and get a nicely formatted and readable QML file.

qmlformat is just for that. It reformats your files, properly indenting them, and reformatting javascript expressions to make them pretty :). While we extensively tested the tool on our own files, we are aware that bugs can happen. As an extra precaution, qmlformat verifies that the semantic structure of the reformatted output matches that of the source file.

This means that files with minor errors cannot be reformatted. This is not always what one wants: Maybe you want get it in shape to actually fix it. So if the file can be parsed the -f/--force command line options disables all the checks, and reformats the file.

By default qmlformat tries to leave the QML object attributes exactly in the order you wrote them. Passing -n/--normalize the object attributes are reordered according to the rules laid out in our coding conventions. This option is especially useful to keep your files in a standardized format, and when comparing files.

qmldom

qmlformat internally uses qmldom, an internal representation of the QML as a tree, that contains imports, qml objects, property definitons and bindings. This representation can be edited, every element can be uniquely identified, and can be updated in a thread safe way. QML Design Studio will use it internally to edit the qml files without having to handle the more cumbersome AST. It is also the basis for the Language Server Protocol implementation we are working on, to make all the new tooling improvements available in the IDE of your choice.

The adventurous can already visualize this internal structure, on which currently we do not give any guarantee of stability, with the following command:

qmldom --dump <MyQmlFile>
This will return a json description of the main things contained in a QML file, including annotations such as deprecations.

Conclusions

We look forward for you to use the new improved versions of qmllint and qmlformat, and let us know about the issues you find. If you encounter any issues, please file a bug on our bugtracker. There is much in store for tooling in upcoming releases and we can't wait to share this with you once it's ready!


Blog Topics:

Comments