Analyse statique QML 2 - Passe personnalisée
Ce chapitre montre comment des passes d'analyse personnalisées peuvent être ajoutées à qmllint, en étendant le plugin que nous avons créé dans le dernier chapitre. À des fins de démonstration, nous allons créer un plugin qui vérifie si les éléments Text ont "Hello world !" assigné à leur propriété text.
Pour ce faire, nous créons une nouvelle classe dérivée de ElementPass.
Remarque : les plugins peuvent enregistrer deux types de passes, ElementPasses et PropertyPasses. Dans ce tutoriel, nous ne considérerons que la passe la plus simple, ElementPass.
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; };
Comme notre HelloWorldElementPass doit analyser les éléments Text, nous avons besoin d'une référence au type Text. Nous pouvons utiliser la fonction resolveType pour l'obtenir. Comme nous ne voulons pas avoir à résoudre constamment le type, nous le faisons une fois dans le constructeur, et nous stockons le type dans une variable membre.
HelloWorldElementPass::HelloWorldElementPass(QQmlSA::PassManager *manager) : QQmlSA::ElementPass(manager) { m_textType = resolveType("QtQuick", "Text"); }
La logique réelle de notre passe se déroule dans deux fonctions : shouldRun et run. Elles s'exécutent sur tous les éléments du fichier analysé par qmllint.
Dans notre méthode shouldRun, nous vérifions si l'élément courant est dérivé de Text, et s'il a un binding sur la propriété 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; }
Seuls les éléments qui passent les vérifications seront alors analysés par notre passe via sa méthode run. Il serait possible d'effectuer toutes les vérifications à l'intérieur de run lui-même, mais il est généralement préférable de séparer les préoccupations - à la fois pour les performances et pour améliorer la lisibilité du code.
Dans notre fonction run, nous récupérons les liaisons avec la propriété text. Si la valeur liée est une chaîne littérale, nous vérifions s'il s'agit du message d'accueil que nous attendons.
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()); } }
Remarque : la plupart du temps, une propriété n'est associée qu'à une seule liaison. Cependant, il peut y avoir par exemple un binding littéral et un Behavior assignés à la même propriété.
Enfin, nous devons créer une instance de notre passe, et l'enregistrer auprès de PassManager. Cela se fait en ajoutant
manager->registerElementPass(std::make_unique<HelloWorldElementPass>(manager));
aux fonctions registerPasses de notre plugin.
Nous pouvons tester notre plugin en invoquant qmllint sur un fichier d'exemple via
qmllint -P /path/to/the/directory/containing/the/plugin --Plugin.HelloWorld.hello-world info test.qml
Si test.qml ressemble à
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!" } } }
nous obtiendrons
Info: test.qml:22:26: Incorrect greeting [Plugin.HelloWorld.hello-world]
MyText { text: "Goodbye world!" }
^^^^^^^^^^^^^^^^
Info: test.qml:19:19: Incorrect greeting [Plugin.HelloWorld.hello-world]
Text { text: "Goodbye world!" }en sortie. Nous pouvons faire quelques observations ici :
- Le premier
Textcontient bien le message d'accueil attendu, il n'y a donc pas d'avertissement - Le second
Textaurait à l'exécution le mauvais avertissement ("Hello"au lieu de"Hello world". Cependant, cela ne peut pas être détecté par qmllint (en général), car il n'y a pas de liaison littérale, mais une liaison à une autre propriété. Comme nous ne vérifions que les liaisons littérales, nous ignorons simplement cette liaison. - Pour la liaison littérale dans le troisième élément
Text, nous avertissons correctement de la mauvaise salutation. - Comme
NotTextne dérive pas deText, l'analyse ne tient pas compte de cet élément, car la vérification deinheritsl'écarte. - L'élément personnalisé
MyTexthérite deText, et par conséquent nous voyons l'avertissement attendu.
En résumé, nous avons vu les étapes nécessaires pour étendre qmllint avec des passes personnalisées, et nous avons également pris conscience des limites des vérifications statiques.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.