qt6-bb10/qtdeclarative/tests/auto/qml/qmllint/lintplugin.cpp

145 lines
5.4 KiB
C++

// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "lintplugin.h"
#include <QtQmlCompiler/private/qqmlsa_p.h>
#include <QtQmlCompiler/private/qqmljstyperesolver_p.h>
using namespace Qt::StringLiterals;
static constexpr QQmlSA::LoggerWarningId plugin{ "testPlugin.test" };
class ElementTest : public QQmlSA::ElementPass
{
public:
ElementTest(QQmlSA::PassManager *manager) : QQmlSA::ElementPass(manager)
{
m_rectangle = resolveType(u"QtQuick", u"Rectangle");
}
bool shouldRun(const QQmlSA::Element &element) override
{
return element.baseType() == m_rectangle;
}
void run(const QQmlSA::Element &element) override
{
auto property = element.property(u"radius"_s);
if (!property.isValid() || element.property(u"radius"_s).typeName() != u"double") {
emitWarning(u"Failed to verify radius property", plugin, element.sourceLocation());
return;
}
auto bindings = element.propertyBindings(u"radius"_s);
if (bindings.isEmpty() || bindings.constFirst().numberValue() != 5) {
emitWarning(u"Failed to verify radius property binding", plugin,
element.sourceLocation());
return;
}
emitWarning(u"ElementTest OK", plugin, element.sourceLocation());
}
private:
QQmlSA::Element m_rectangle;
};
class PropertyTest : public QQmlSA::PropertyPass
{
public:
PropertyTest(QQmlSA::PassManager *manager)
: QQmlSA::PropertyPass(manager)
, m_manager(manager) { }
void onBinding(const QQmlSA::Element &element, const QString &propertyName,
const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope,
const QQmlSA::Element &value) override
{
auto resolver = QQmlSA::PassManagerPrivate::resolver(*m_manager);
if (resolver->jsGlobalObject().isNull()) {
emitWarning(u"Type resolution is broken", plugin);
return;
}
emitWarning(u"Saw binding on %1 property %2 with value %3 (and type %4) in scope %5"_s
.arg(element.baseTypeName(), propertyName,
value.isNull()
? u"NULL"_s
: (value.name().isNull() ? value.baseTypeName()
: value.name()))
.arg(qToUnderlying(binding.bindingType()))
.arg(bindingScope.baseTypeName()),
plugin, bindingScope.sourceLocation());
}
void onRead(const QQmlSA::Element &element, const QString &propertyName,
const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override
{
emitWarning(u"Saw read on %1 property %2 in scope %3"_s.arg(
element.baseTypeName(), propertyName, readScope.baseTypeName()),
plugin, location);
}
void onWrite(const QQmlSA::Element &element, const QString &propertyName,
const QQmlSA::Element &value, const QQmlSA::Element &writeScope,
QQmlSA::SourceLocation location) override
{
emitWarning(u"Saw write on %1 property %2 with value %3 in scope %4"_s.arg(
element.baseTypeName(), propertyName,
(value.name().isNull() ? value.baseTypeName()
: value.name()),
writeScope.baseTypeName()),
plugin, location);
}
private:
QQmlSA::PassManager *m_manager;
};
class HasImportedModuleTest : public QQmlSA::ElementPass
{
public:
HasImportedModuleTest(QQmlSA::PassManager *manager, QString message)
: QQmlSA::ElementPass(manager), m_message(message)
{
}
bool shouldRun(const QQmlSA::Element &element) override
{
Q_UNUSED(element)
return true;
}
void run(const QQmlSA::Element &element) override
{
Q_UNUSED(element)
emitWarning(m_message, plugin);
}
private:
QString m_message;
};
void LintPlugin::registerPasses(QQmlSA::PassManager *manager, const QQmlSA::Element &rootElement)
{
if (!rootElement.filePath().endsWith(u"_pluginTest.qml"))
return;
manager->registerElementPass(std::make_unique<ElementTest>(manager));
manager->registerPropertyPass(std::make_unique<PropertyTest>(manager), "QtQuick", "Text",
"text");
manager->registerPropertyPass(std::make_unique<PropertyTest>(manager), "", "", "x");
manager->registerPropertyPass(std::make_unique<PropertyTest>(manager), "", "", "log");
manager->registerPropertyPass(std::make_unique<PropertyTest>(manager), "QtQuick", "ListView");
if (manager->hasImportedModule("QtQuick.Controls")) {
if (manager->hasImportedModule("QtQuick")) {
if (manager->hasImportedModule("QtQuick.Window")) {
manager->registerElementPass(std::make_unique<HasImportedModuleTest>(
manager, "QtQuick.Controls, QtQuick and QtQuick.Window present"));
}
} else {
manager->registerElementPass(std::make_unique<HasImportedModuleTest>(
manager, "QtQuick.Controls and NO QtQuick present"));
}
}
}