diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/plugins/qmllint/quick/plugin.json | 5 | ||||
| -rw-r--r-- | src/plugins/qmllint/quick/quicklintplugin.cpp | 53 | ||||
| -rw-r--r-- | src/plugins/qmllint/quick/quicklintplugin.h | 12 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 4 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmlsa.cpp | 10 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmlsa_p.h | 4 |
6 files changed, 87 insertions, 1 deletions
diff --git a/src/plugins/qmllint/quick/plugin.json b/src/plugins/qmllint/quick/plugin.json index 442a693b7b..527e6002b4 100644 --- a/src/plugins/qmllint/quick/plugin.json +++ b/src/plugins/qmllint/quick/plugin.json @@ -29,6 +29,11 @@ "name": "unexpected-var-type", "settingsName": "UnexpectedVarType", "description": "Warn about incompatible types being set on var properties" + }, + { + "name": "property-changes-parsed", + "settingsName": "PropertyChangesParsed", + "description": "Warn about legacy PropertyChanges that rely on the custom parser" } ] } diff --git a/src/plugins/qmllint/quick/quicklintplugin.cpp b/src/plugins/qmllint/quick/quicklintplugin.cpp index 3b89635748..f040d57849 100644 --- a/src/plugins/qmllint/quick/quicklintplugin.cpp +++ b/src/plugins/qmllint/quick/quicklintplugin.cpp @@ -4,6 +4,7 @@ #include "quicklintplugin.h" #include <QtQmlCompiler/private/qqmljslogger_p.h> +#include <QtQmlCompiler/private/qqmljsutils_p.h> QT_BEGIN_NAMESPACE @@ -14,6 +15,7 @@ static constexpr LoggerWarningId quickAttachedPropertyType { "Quick.attached-pro static constexpr LoggerWarningId quickControlsNativeCustomize { "Quick.controls-native-customize" }; static constexpr LoggerWarningId quickAnchorCombinations { "Quick.anchor-combinations" }; static constexpr LoggerWarningId quickUnexpectedVarType { "Quick.unexpected-var-type" }; +static constexpr LoggerWarningId quickPropertyChangesParsed { "Quick.property-changes-parsed" }; ForbiddenChildrenPropertyValidatorPass::ForbiddenChildrenPropertyValidatorPass( QQmlSA::PassManager *manager) @@ -520,6 +522,7 @@ void QmlLintQuickPlugin::registerPasses(QQmlSA::PassManager *manager, if (hasQuick) { manager->registerElementPass(std::make_unique<AnchorsValidatorPass>(manager)); + manager->registerElementPass(std::make_unique<PropertyChangesValidatorPass>(manager)); auto forbiddenChildProperty = std::make_unique<ForbiddenChildrenPropertyValidatorPass>(manager); @@ -636,6 +639,56 @@ void QmlLintQuickPlugin::registerPasses(QQmlSA::PassManager *manager, manager->registerElementPass(std::make_unique<ControlsNativeValidatorPass>(manager)); } +PropertyChangesValidatorPass::PropertyChangesValidatorPass(QQmlSA::PassManager *manager) + : QQmlSA::ElementPass(manager) +{ + m_propertyChanges = resolveType("QtQuick", "PropertyChanges"); +} + +bool PropertyChangesValidatorPass::shouldRun(const QQmlSA::Element &element) +{ + return !m_propertyChanges.isNull() && element->inherits(m_propertyChanges); +} + +void PropertyChangesValidatorPass::run(const QQmlSA::Element &element) +{ + const QMultiHash<QString, QQmlJSMetaPropertyBinding> bindings = element->ownPropertyBindings(); + + const auto target = bindings.find(u"target"_s); + if (target == bindings.end()) + return; + + QString targetId = u"<id>"_s; + const QString targetBinding = sourceCode(target->sourceLocation()); + const QQmlSA::Element targetElement = resolveId(targetBinding, element); + if (!targetElement.isNull()) + targetId = targetBinding; + + for (auto it = bindings.begin(), end = bindings.end(); it != end; ++it) { + const QString name = it->propertyName(); + if (element->hasProperty(name)) + continue; + + const QQmlJS::SourceLocation bindingLocation = it->sourceLocation(); + if (!targetElement->hasProperty(name)) { + emitWarning( + "Unknown property \"%1\" in PropertyChanges."_L1.arg(name), + quickPropertyChangesParsed, bindingLocation); + continue; + } + + QString binding = sourceCode(bindingLocation); + if (binding.length() > 16) + binding = binding.left(13) + "..."_L1; + + emitWarning( + "Property \"%1\" is custom-parsed in PropertyChanges. " + "You should phrase this binding as \"%2.%1: %3\""_L1 + .arg(name, targetId, binding), + quickPropertyChangesParsed, bindingLocation); + } +} + QT_END_NAMESPACE #include "moc_quicklintplugin.cpp" diff --git a/src/plugins/qmllint/quick/quicklintplugin.h b/src/plugins/qmllint/quick/quicklintplugin.h index be368f0880..9db2fff5cf 100644 --- a/src/plugins/qmllint/quick/quicklintplugin.h +++ b/src/plugins/qmllint/quick/quicklintplugin.h @@ -139,6 +139,18 @@ private: QMultiHash<QString, QQmlSA::Element> m_expectedPropertyTypes; }; +class PropertyChangesValidatorPass : public QQmlSA::ElementPass +{ +public: + PropertyChangesValidatorPass(QQmlSA::PassManager *manager); + + bool shouldRun(const QQmlSA::Element &element) override; + void run(const QQmlSA::Element &element) override; + +private: + QQmlSA::Element m_propertyChanges; +}; + QT_END_NAMESPACE #endif // QUICKLINTPLUGIN_H diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index 48c4bcbeef..0f79034bc6 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -1773,7 +1773,9 @@ QQmlJSImportVisitor::parseBindingExpression(const QString &name, } auto expr = exprStatement->expression; - QQmlJSMetaPropertyBinding binding(expr->firstSourceLocation(), name); + QQmlJSMetaPropertyBinding binding( + combine(expr->firstSourceLocation(), expr->lastSourceLocation()), + name); bool isUndefinedBinding = false; diff --git a/src/qmlcompiler/qqmlsa.cpp b/src/qmlcompiler/qqmlsa.cpp index 0b6e88ef7c..9dde74ad86 100644 --- a/src/qmlcompiler/qqmlsa.cpp +++ b/src/qmlcompiler/qqmlsa.cpp @@ -49,6 +49,16 @@ Element GenericPass::resolveLiteralType(const QQmlJSMetaPropertyBinding &binding return binding.literalType(d->manager->m_typeResolver); } +Element GenericPass::resolveId(QAnyStringView id, const Element &context) +{ + return d->manager->m_typeResolver->scopeForId(id.toString(), context); +} + +QString GenericPass::sourceCode(QQmlJS::SourceLocation location) +{ + return d->manager->m_visitor->logger()->code().mid(location.offset, location.length); +} + /*! * \brief PassManager::registerElementPass registers ElementPass with the pass manager. diff --git a/src/qmlcompiler/qqmlsa_p.h b/src/qmlcompiler/qqmlsa_p.h index 67b6995b54..e43ba9ed4e 100644 --- a/src/qmlcompiler/qqmlsa_p.h +++ b/src/qmlcompiler/qqmlsa_p.h @@ -50,6 +50,10 @@ public: QQmlJS::SourceLocation srcLocation = QQmlJS::SourceLocation()); Element resolveType(QAnyStringView moduleName, QAnyStringView typeName); // #### TODO: revisions Element resolveLiteralType(const QQmlJSMetaPropertyBinding &binding); + Element resolveId(QAnyStringView id, const Element &context); + + QString sourceCode(QQmlJS::SourceLocation location); + private: std::unique_ptr<GenericPassPrivate> d; // PIMPL might be overkill |
