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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
m_savedBindingOuterScope = m_currentScope;
|
||||
|
@ -1589,9 +1607,17 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
|
|||
if (name.isEmpty())
|
||||
break;
|
||||
|
||||
enterEnvironmentNonUnique(name.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
|
||||
: QQmlJSScope::GroupedPropertyScope,
|
||||
const bool isAttachedProperty = name.front().isUpper();
|
||||
if (isAttachedProperty) {
|
||||
// attached property
|
||||
enterEnvironmentNonUnique(QQmlJSScope::AttachedPropertyScope,
|
||||
name, group->firstSourceLocation());
|
||||
} else {
|
||||
// grouped property
|
||||
enterEnvironmentNonUnique(QQmlJSScope::GroupedPropertyScope,
|
||||
name, group->firstSourceLocation());
|
||||
createGroupBinding(m_currentScope, name, group->firstSourceLocation());
|
||||
}
|
||||
}
|
||||
|
||||
auto name = group->name;
|
||||
|
@ -1982,7 +2008,12 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
|
|||
|
||||
const auto scopeKind = idName.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
|
||||
: QQmlJSScope::GroupedPropertyScope;
|
||||
|
||||
bool exists = enterEnvironmentNonUnique(scopeKind, idName, group->firstSourceLocation());
|
||||
|
||||
if (scopeKind == QQmlJSScope::GroupedPropertyScope)
|
||||
createGroupBinding(m_currentScope, idName, group->firstSourceLocation());
|
||||
|
||||
++scopesEnteredCounter;
|
||||
needsResolution = needsResolution || !exists;
|
||||
}
|
||||
|
|
|
@ -466,7 +466,23 @@ private:
|
|||
friend bool operator!=(AttachedProperty a, AttachedProperty b) { return !(a == b); }
|
||||
};
|
||||
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); }
|
||||
};
|
||||
using type = std::variant<Invalid, BoolLiteral, NumberLiteral, StringLiteral,
|
||||
|
@ -530,6 +546,12 @@ public:
|
|||
m_bindingContent = Content::Script {};
|
||||
}
|
||||
|
||||
void setGroupBinding(const QSharedPointer<const QQmlJSScope> &groupScope)
|
||||
{
|
||||
ensureSetBindingTypeOnce();
|
||||
m_bindingContent = Content::GroupProperty { groupScope };
|
||||
}
|
||||
|
||||
void setBoolLiteral(bool value)
|
||||
{
|
||||
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/qqmljsimportvisitor_p.h>
|
||||
#include <private/qqmljstyperesolver_p.h>
|
||||
#include <QtQml/private/qqmljslexer_p.h>
|
||||
#include <QtQml/private/qqmljsparser_p.h>
|
||||
|
||||
class tst_qqmljsscope : public QQmlDataTest
|
||||
{
|
||||
|
@ -95,11 +97,13 @@ private Q_SLOTS:
|
|||
void signalCreationDifferences();
|
||||
void allTypesAvailable();
|
||||
void shadowing();
|
||||
|
||||
#ifdef LABS_QML_MODELS_PRESENT
|
||||
void componentWrappedObjects();
|
||||
void labsQmlModelsSanity();
|
||||
#endif
|
||||
void unknownCppBase();
|
||||
void groupedProperties();
|
||||
|
||||
public:
|
||||
tst_qqmljsscope()
|
||||
|
@ -262,5 +266,15 @@ void tst_qqmljsscope::unknownCppBase()
|
|||
// 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)
|
||||
#include "tst_qqmljsscope.moc"
|
||||
|
|
Loading…
Reference in New Issue