qmlcompiler: Improve grouped property support
Still lacks support for merging and resolving grouped bindings, but this will be handled in another patch. Task-number: QTBUG-100168 Original-patch-by: Fabian Kosmale <fabian.kosmale@qt.io> Change-Id: I1bb73f383acc3c8512676db47c5944f369b904b7 Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
parent
5fc74d216f
commit
bc63196948
|
@ -1574,6 +1574,24 @@ void QQmlJSImportVisitor::handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scri
|
||||||
m_scopesById.insert(name, m_currentScope);
|
m_scopesById.insert(name, m_currentScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void createGroupBinding(QQmlJSScope::Ptr &scope, const QString &name,
|
||||||
|
const QQmlJS::SourceLocation &srcLocation)
|
||||||
|
{
|
||||||
|
auto parentScope = scope->parentScope();
|
||||||
|
const auto propertyBindings = parentScope->ownPropertyBindings(name);
|
||||||
|
const bool alreadyHasGroupedBinding = std::any_of(
|
||||||
|
propertyBindings.first, propertyBindings.second,
|
||||||
|
[](const QQmlJSMetaPropertyBinding &binding) {
|
||||||
|
return binding.bindingType() == QQmlJSMetaPropertyBinding::GroupProperty;
|
||||||
|
});
|
||||||
|
if (alreadyHasGroupedBinding)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QQmlJSMetaPropertyBinding groupBinding(srcLocation, name);
|
||||||
|
groupBinding.setGroupBinding(static_cast<QSharedPointer<QQmlJSScope>>(scope));
|
||||||
|
parentScope->addOwnPropertyBinding(std::move(groupBinding));
|
||||||
|
}
|
||||||
|
|
||||||
bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
|
bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
|
||||||
{
|
{
|
||||||
m_savedBindingOuterScope = m_currentScope;
|
m_savedBindingOuterScope = m_currentScope;
|
||||||
|
@ -1589,9 +1607,17 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
|
||||||
if (name.isEmpty())
|
if (name.isEmpty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
enterEnvironmentNonUnique(name.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
|
const bool isAttachedProperty = name.front().isUpper();
|
||||||
: QQmlJSScope::GroupedPropertyScope,
|
if (isAttachedProperty) {
|
||||||
|
// attached property
|
||||||
|
enterEnvironmentNonUnique(QQmlJSScope::AttachedPropertyScope,
|
||||||
name, group->firstSourceLocation());
|
name, group->firstSourceLocation());
|
||||||
|
} else {
|
||||||
|
// grouped property
|
||||||
|
enterEnvironmentNonUnique(QQmlJSScope::GroupedPropertyScope,
|
||||||
|
name, group->firstSourceLocation());
|
||||||
|
createGroupBinding(m_currentScope, name, group->firstSourceLocation());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name = group->name;
|
auto name = group->name;
|
||||||
|
@ -1982,7 +2008,12 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
|
||||||
|
|
||||||
const auto scopeKind = idName.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
|
const auto scopeKind = idName.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
|
||||||
: QQmlJSScope::GroupedPropertyScope;
|
: QQmlJSScope::GroupedPropertyScope;
|
||||||
|
|
||||||
bool exists = enterEnvironmentNonUnique(scopeKind, idName, group->firstSourceLocation());
|
bool exists = enterEnvironmentNonUnique(scopeKind, idName, group->firstSourceLocation());
|
||||||
|
|
||||||
|
if (scopeKind == QQmlJSScope::GroupedPropertyScope)
|
||||||
|
createGroupBinding(m_currentScope, idName, group->firstSourceLocation());
|
||||||
|
|
||||||
++scopesEnteredCounter;
|
++scopesEnteredCounter;
|
||||||
needsResolution = needsResolution || !exists;
|
needsResolution = needsResolution || !exists;
|
||||||
}
|
}
|
||||||
|
|
|
@ -466,7 +466,23 @@ private:
|
||||||
friend bool operator!=(AttachedProperty a, AttachedProperty b) { return !(a == b); }
|
friend bool operator!=(AttachedProperty a, AttachedProperty b) { return !(a == b); }
|
||||||
};
|
};
|
||||||
struct GroupProperty {
|
struct GroupProperty {
|
||||||
friend bool operator==(GroupProperty , GroupProperty ) { return true; }
|
/* Given a group property declaration like
|
||||||
|
anchors.left: root.left
|
||||||
|
the QQmlJSMetaPropertyBinding will have name "anchors", and a m_bindingContent
|
||||||
|
of type GroupProperty, with groupScope pointing to the scope introudced by anchors
|
||||||
|
In that scope, there will be another QQmlJSMetaPropertyBinding, with name "left" and
|
||||||
|
m_bindingContent Script (for root.left).
|
||||||
|
There should never be more than one GroupProperty for the same name in the same
|
||||||
|
scope, though: If the scope also contains anchors.top: root.top that should reuse the
|
||||||
|
GroupProperty content (and add a top: root.top binding in it). There might however
|
||||||
|
still be an additional object or script binding ( anchors: {left: foo, right: bar };
|
||||||
|
anchors: root.someFunction() ) or another binding to the property in a "derived"
|
||||||
|
type.
|
||||||
|
|
||||||
|
### TODO: Obtaining the effective binding result requires some resolving function
|
||||||
|
*/
|
||||||
|
QWeakPointer<const QQmlJSScope> groupScope;
|
||||||
|
friend bool operator==(GroupProperty a, GroupProperty b) { return a.groupScope == b.groupScope; }
|
||||||
friend bool operator!=(GroupProperty a, GroupProperty b) { return !(a == b); }
|
friend bool operator!=(GroupProperty a, GroupProperty b) { return !(a == b); }
|
||||||
};
|
};
|
||||||
using type = std::variant<Invalid, BoolLiteral, NumberLiteral, StringLiteral,
|
using type = std::variant<Invalid, BoolLiteral, NumberLiteral, StringLiteral,
|
||||||
|
@ -530,6 +546,12 @@ public:
|
||||||
m_bindingContent = Content::Script {};
|
m_bindingContent = Content::Script {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setGroupBinding(const QSharedPointer<const QQmlJSScope> &groupScope)
|
||||||
|
{
|
||||||
|
ensureSetBindingTypeOnce();
|
||||||
|
m_bindingContent = Content::GroupProperty { groupScope };
|
||||||
|
}
|
||||||
|
|
||||||
void setBoolLiteral(bool value)
|
void setBoolLiteral(bool value)
|
||||||
{
|
{
|
||||||
ensureSetBindingTypeOnce();
|
ensureSetBindingTypeOnce();
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.top: parent.top
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
GroupBase {
|
||||||
|
anchors.left: parent.right
|
||||||
|
}
|
|
@ -44,6 +44,8 @@
|
||||||
#include <private/qqmljslogger_p.h>
|
#include <private/qqmljslogger_p.h>
|
||||||
#include <private/qqmljsimportvisitor_p.h>
|
#include <private/qqmljsimportvisitor_p.h>
|
||||||
#include <private/qqmljstyperesolver_p.h>
|
#include <private/qqmljstyperesolver_p.h>
|
||||||
|
#include <QtQml/private/qqmljslexer_p.h>
|
||||||
|
#include <QtQml/private/qqmljsparser_p.h>
|
||||||
|
|
||||||
class tst_qqmljsscope : public QQmlDataTest
|
class tst_qqmljsscope : public QQmlDataTest
|
||||||
{
|
{
|
||||||
|
@ -95,11 +97,13 @@ private Q_SLOTS:
|
||||||
void signalCreationDifferences();
|
void signalCreationDifferences();
|
||||||
void allTypesAvailable();
|
void allTypesAvailable();
|
||||||
void shadowing();
|
void shadowing();
|
||||||
|
|
||||||
#ifdef LABS_QML_MODELS_PRESENT
|
#ifdef LABS_QML_MODELS_PRESENT
|
||||||
void componentWrappedObjects();
|
void componentWrappedObjects();
|
||||||
void labsQmlModelsSanity();
|
void labsQmlModelsSanity();
|
||||||
#endif
|
#endif
|
||||||
void unknownCppBase();
|
void unknownCppBase();
|
||||||
|
void groupedProperties();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tst_qqmljsscope()
|
tst_qqmljsscope()
|
||||||
|
@ -262,5 +266,15 @@ void tst_qqmljsscope::unknownCppBase()
|
||||||
// we should not crash here, then it is a success
|
// we should not crash here, then it is a success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qqmljsscope::groupedProperties()
|
||||||
|
{
|
||||||
|
QQmlJSScope::ConstPtr root = run(u"groupProperties.qml"_qs);
|
||||||
|
QVERIFY(root);
|
||||||
|
|
||||||
|
QVERIFY(root->hasProperty(u"anchors"_qs));
|
||||||
|
auto anchorBindings = root->propertyBindings(u"anchors"_qs);
|
||||||
|
QVERIFY(!anchorBindings.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_qqmljsscope)
|
QTEST_MAIN(tst_qqmljsscope)
|
||||||
#include "tst_qqmljsscope.moc"
|
#include "tst_qqmljsscope.moc"
|
||||||
|
|
Loading…
Reference in New Issue