qmllint: Do not warn about unnotifiable properties outside bindings
It doesn't cause any harm if we are not inside a binding. There's a slight issue with the fact that we now don't warn if one extracts the read into a separate function, and calls the function inside a binding, but that is still better than spurious warnings. Fix this by checking in which context the read occurs. We currently rely on a "magic" name we give to the function's scope if it as a binding, but this will be fixed in a follow up commit introducing new scope types. We don't want to do introduce them here, as they would be new API not suitable for picking back to 6.10. Another open issue is that the onRead handler gets the outer QML scope as the context, which necessiates that we traverse its child scopes to find the actual function. Fixing that would necessiate some larger work in the QQmlTypePropagator, and is consequently deferred to another patch, too. Pick-to: 6.10 Fixes: QTBUG-138346 Change-Id: I29ea39eb32a18d9b54ded8d5e2c9a5f66051374f Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
4985e06e53
commit
740d67fbca
|
@ -2486,7 +2486,8 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
|
|||
leaveEnvironment();
|
||||
}
|
||||
|
||||
enterEnvironment(QQmlSA::ScopeType::JSFunctionScope, QStringLiteral("binding"),
|
||||
enterEnvironment(QQmlSA::ScopeType::JSFunctionScope,
|
||||
signal ? u"changeHandler"_s : u"binding"_s,
|
||||
scriptBinding->statement->firstSourceLocation());
|
||||
|
||||
return true;
|
||||
|
|
|
@ -506,6 +506,10 @@ void QQmlJSLinter::processMessages(QJsonArray &warnings)
|
|||
});
|
||||
}
|
||||
|
||||
static bool scopeIsBinding(const QQmlJSScope::ConstPtr& scope) {
|
||||
return scope->scopeType() == QQmlJSScope::ScopeType::JSFunctionScope && scope->baseTypeName() == u"binding";
|
||||
}
|
||||
|
||||
QQmlJSLinter::LintResult QQmlJSLinter::lintFile(const QString &filename,
|
||||
const QString *fileContents, const bool silent,
|
||||
QJsonArray *json, const QStringList &qmlImportPaths,
|
||||
|
@ -673,15 +677,27 @@ QQmlJSLinter::LintResult QQmlJSLinter::lintFile(const QString &filename,
|
|||
|
||||
QQmlSA::PropertyPassBuilder(passMan.get())
|
||||
.withOnRead([](QQmlSA::PropertyPass *self, const QQmlSA::Element &element,
|
||||
const QString &propName, const QQmlSA::Element &readScope,
|
||||
const QString &propName, const QQmlSA::Element &readScope_,
|
||||
QQmlSA::SourceLocation location) {
|
||||
Q_UNUSED(readScope);
|
||||
|
||||
const auto &elementScope = QQmlJSScope::scope(element);
|
||||
const auto &owner = QQmlJSScope::ownerOfProperty(elementScope, propName).scope;
|
||||
if (!owner || owner->isComposite() || owner->isValueType())
|
||||
return;
|
||||
const auto &prop = QQmlSA::PropertyPrivate::property(element.property(propName));
|
||||
if (prop.index() != -1 && !prop.isPropertyConstant() && prop.notify().isEmpty()) {
|
||||
const QQmlJSScope::ConstPtr &readScope = QQmlJSScope::scope(readScope_);
|
||||
// FIXME: we currently get the closest QML Scope as readScope, instead of
|
||||
// the innermost scope. We try locate it here via source location
|
||||
Q_ASSERT(readScope->scopeType() == QQmlJSScope::ScopeType::QMLScope);
|
||||
for (auto it = readScope->childScopesBegin(); it != readScope->childScopesEnd(); ++it) {
|
||||
QQmlJS::SourceLocation childLocation = (*it)->sourceLocation();
|
||||
if ( childLocation.offset <= location.offset() &&
|
||||
(childLocation.offset + childLocation.length <= location.offset() + location.length()) ) {
|
||||
if (!scopeIsBinding(*it))
|
||||
return;
|
||||
}
|
||||
}
|
||||
const QString msg =
|
||||
"Reading non-constant and non-notifiable property %1. "_L1
|
||||
"Binding might not update when the property changes."_L1.arg(propName);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import QtQuick
|
||||
Item {
|
||||
DropArea {
|
||||
onDropped: (drop) => {
|
||||
console.log(drop.hasUrls)
|
||||
}
|
||||
}
|
||||
|
||||
function f(drop: DragEvent) {
|
||||
console.log(drop.hasUrls)
|
||||
}
|
||||
}
|
|
@ -2072,6 +2072,7 @@ void TestQmllint::cleanQmlCode_data()
|
|||
QTest::newRow("uiQml") << QStringLiteral("FormUser.qml");
|
||||
QTest::newRow("unexportedCppBase") << QStringLiteral("unexportedCppBase.qml");
|
||||
QTest::newRow("unknownBuiltinFont") << QStringLiteral("ButtonLoader.qml");
|
||||
QTest::newRow("unnotifiableReadOutsideBinding") << QStringLiteral("unnotifiableReadOutsideBinding.qml");
|
||||
QTest::newRow("v4SequenceMethods") << QStringLiteral("v4SequenceMethods.qml");
|
||||
QTest::newRow("valueSource") << QStringLiteral("valueSource.qml");
|
||||
QTest::newRow("var") << QStringLiteral("var.qml");
|
||||
|
|
Loading…
Reference in New Issue