qml_static_analyzer 0.1.0

A static analyzer for QML files
Documentation

QML Static Analyzer

This tool is an experimental static analyzer for QML code. It detects type errors, undefined names, incorrect signal handlers, and other common issues without running the application.

It was created because qmllint produced a large number of false positives and was generally difficult to use effectively in our project.

The tool was primarily developed for internal use, where we rely on it to analyze large QML codebases. However, maybe someone will find it useful as well.

It doesn't need to compile project - it works by parsing QML files and analyzing their structure, hierarchy and expressions, so it is really easy to set up and use especially in CI.

What it detects

Error Example
Property redefinition property int height in a Rectangle (already defined by Qt)
Property type mismatch property int foo: false (bool literal, not int)
Property ref type mismatch property bool b: otherIntProp (int property assigned to bool)
Assignment to unknown property Layout.notExist: true
Assignment type mismatch Layout.fillWidth: 21 (expects bool, got int)
Undefined name in function zzzz = x + y where zzzz is not declared anywhere in scope
Unknown signal handler onStatussChanged (typo — no such signal or property)
Unknown member access elem.nonExistingProp = true
Member assignment type mismatch elem.boolProp = 0 (int assigned to bool member)
Undefined name in property expression property bool foo: undeclared.bar
Unknown type Sub3 { } when Sub3 is not defined anywhere in the project
Unknown C++ member diskManager.nonExisting when header reveals actual members

Building

# Build without embedded Qt types (type DB must be provided at runtime)
cargo build --release

# Build with Qt types embedded in the binary
INCLUDED_QT_TYPES=qt_types_6.3.2.json cargo build --release

# Build with multiple Qt versions embedded
INCLUDED_QT_TYPES="qt_types_6.3.2.json,qt_types_6.8.3.json" cargo build --release

Generating the Qt types database

The analyzer needs a JSON file that describes Qt's built-in types. Without it, app would be useless, so this is required. Generate it from an installed Qt:

# First build the tool
cargo build

# Then generate (point at Qt's gcc_64 directory)
target/debug/qml_static_analyzer generate-qt-types --qt-path ~/Qt/6.3.2/gcc_64
# → produces qt_types_6.3.2.json

# Custom output path or version string
target/debug/qml_static_analyzer generate-qt-types \
    --qt-path ~/Qt/6.8.3/gcc_64 \
    --output my_types.json \
    --qt-version 6.8.3

In repo, there are already generated type DB files for Qt 6.3.2 and 6.8.3 that you can use directly or you can generate your own for different versions.

Usage

Basic check

# With type DB embedded in the binary
qml_static_analyzer check --path src/ --builtin-qt-version 6.3.2

# With type DB loaded from file at runtime
qml_static_analyzer check --path src/ --qt-types-json qt_types_6.3.2.json

# With both config file and type DB
qml_static_analyzer check --path src/ --config project.toml --qt-types-json qt_types_6.3.2.json

# With verbose error paths and type DB embedded in the binary
qml_static_analyzer check --path src/ --builtin-qt-version 6.3.2 --complex

# List all built-in Qt types
qml_static_analyzer list-builtins

Config file

Not everything can be detected by static analysis, and some projects may have specific patterns that cause false positives. A config file allows you to ignore specific folders/files, include additional informations about C++ classes and

Suppressing individual errors

Add // qml-ignore at the end of a line to suppress any error reported on that line:

invalidProperty2: 123 // qml-ignore

By default, a warning is emitted if a // qml-ignore comment does not suppress any actual error (i.e. it is useless). Disable this with --no-warn-useless-ignore.

Known limitations

  • Expressions are not type-checked. Only simple literals and single-property references are checked for type compatibility. property int x: a + b is accepted without checking a and b.
  • var properties are unchecked. Any assignment to a var-typed property is accepted.
  • Function return types are not tracked. Member access on function call results is not validated.
  • JS variable scope is simplified. let/const/var declarations are collected but not strictly scoped within blocks.
  • Enum member existence is not validated. Text.AlignLeft is accepted if Text is a known Qt type, without checking whether AlignLeft actually exists.
  • Loader source: files are not checked for existence. The type name is extracted from the path string but the file is not verified.
  • Unused imports are not detected (planned).
  • C++ header parsing is basic. Uses pattern matching for Q_PROPERTY, signals, and slots. Complex macro expansions may not be recognized.

AI usage

This tool was developed with extensive assistance from AI, guided and directed by humans to accelerate development.