Análisis estático QML 2 - Pase personalizado
Este capítulo muestra cómo se pueden añadir pases de análisis personalizados a qmllint, ampliando el plugin que hemos creado en el capítulo anterior. A modo de demostración, crearemos un complemento que compruebe si los elementos Text tienen "Hello world!" asignado a su propiedad text.
Para ello, crearemos una nueva clase derivada de ElementPass.
Nota: Hay dos tipos de pases que los plugins pueden registrar, ElementPasses, y PropertyPasses. En este tutorial, sólo consideraremos el más 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; };
Como nuestro HelloWorldElementPass debe analizar elementos Text, necesitamos una referencia al tipo Text. Podemos utilizar la función resolveType para obtenerla. Como no queremos volver a resolver constantemente el tipo, lo hacemos una vez en el constructor, y almacenamos el tipo en una variable miembro.
HelloWorldElementPass::HelloWorldElementPass(QQmlSA::PassManager *manager) : QQmlSA::ElementPass(manager) { m_textType = resolveType("QtQuick", "Text"); }
La lógica real de nuestro pase ocurre en dos funciones: shouldRun y run. Se ejecutarán en todos los elementos del archivo analizado por qmllint.
En nuestro método shouldRun, comprobamos si el elemento actual deriva de Text y si tiene un enlace a la propiedad 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; }
Sólo los elementos que pasen las comprobaciones serán analizados por nuestro pass a través de su método run. Sería posible realizar todas las comprobaciones dentro del propio run, pero generalmente es preferible tener una separación de intereses, tanto por rendimiento como para mejorar la legibilidad del código.
En nuestra función run, recuperamos los enlaces a la propiedad text. Si el valor vinculado es un literal de cadena, comprobamos si es el saludo que esperamos.
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()); } }
Nota: La mayoría de las veces, una propiedad sólo tendrá asignada una vinculación. Sin embargo, puede haber, por ejemplo, un enlace literal y un Behavior asignados a la misma propiedad.
Por último, tenemos que crear una instancia de nuestro pase y registrarla con PassManager. Esto se hace añadiendo
manager->registerElementPass(std::make_unique<HelloWorldElementPass>(manager));
a las funciones registerPasses de nuestro plugin.
Podemos probar nuestro plugin invocando qmllint en un archivo de ejemplo mediante
qmllint -P /path/to/the/directory/containing/the/plugin --Plugin.HelloWorld.hello-world info test.qml
Si test.qml se parece a
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!" } } }
obtendremos
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!" }como salida. Podemos hacer algunas observaciones aquí:
- El primer
Textcontiene el saludo esperado, por lo que no hay advertencia. - El segundo
Texttendría en tiempo de ejecución la advertencia incorrecta ("Hello"en lugar de"Hello world". Sin embargo, esto no puede ser detectado por qmllint (en general), ya que no hay vinculación literal, sino una vinculación a otra propiedad. Como sólo comprobamos los enlaces literales, simplemente pasamos por alto este enlace. - Para la vinculación literal en el tercer elemento
Text, advertimos correctamente sobre el saludo incorrecto. - Como
NotTextno deriva deText, el análisis lo omitirá, ya que la comprobación deinheritslo descartará. - El elemento personalizado
MyTexthereda deText, y en consecuencia vemos la advertencia esperada.
En resumen, hemos visto los pasos necesarios para extender qmllint con pases personalizados, y también hemos tomado conciencia de las limitaciones de las comprobaciones estáticas.
© 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.