aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlls
diff options
context:
space:
mode:
authorSami Shalayel <sami.shalayel@qt.io>2024-03-25 16:15:17 +0100
committerSami Shalayel <sami.shalayel@qt.io>2024-04-05 17:45:42 +0200
commitadb1fb57d8f4a8cb894457af6506f301d5401032 (patch)
treec9eab42bef1aa4dfe47b36fbbe3ecf1715b559cb /src/qmlls
parent4c4605be79e564921699a065df58333d3ee10d59 (diff)
qmlls: test deferred/generalized grouped properties in qmlls
Change propertyBindingFromReferrerScope() to accept a TypeResolver as parameter, and use it to resolve ids for bindings to deferred non-properties. Add a comment explaining why deferred non-properties are ids and remove the previously existing confusing comment. Do not discard the expression type or the expression name if the scope was not found, and just leave the semantic scope from the returned value out. Add some tests for deferred grouped properties in qmlls and add some fixes to make the tests run. Fixes: QTBUG-123618 Change-Id: If56945acfc84b092c07760bbefe74825193c8808 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qmlls')
-rw-r--r--src/qmlls/qqmllsutils.cpp109
1 files changed, 59 insertions, 50 deletions
diff --git a/src/qmlls/qqmllsutils.cpp b/src/qmlls/qqmllsutils.cpp
index f5f13ffef0..6de3f574d0 100644
--- a/src/qmlls/qqmllsutils.cpp
+++ b/src/qmlls/qqmllsutils.cpp
@@ -1071,12 +1071,12 @@ methodFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStrin
findDefiningScopeForMethod(current, name),
*type };
case ResolveActualTypeForFieldMemberExpression:
- // not implemented, but JS functions have methods and properties
- // see
+ // QQmlJSScopes were not implemented for methods yet, but JS functions have methods
+ // and properties see
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
- // for the list of properties/methods of functions
+ // for the list of properties/methods of functions. Therefore return a null scope.
// see also code below for non-qualified method access
- return {};
+ return QQmlLSUtilsExpressionType{ name, {}, *type };
}
}
@@ -1090,7 +1090,7 @@ methodFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStrin
};
case ResolveActualTypeForFieldMemberExpression:
// Properties and methods of JS methods are not supported yet
- return {};
+ return QQmlLSUtilsExpressionType{ name, {}, SignalHandlerIdentifier };
}
}
}
@@ -1131,58 +1131,67 @@ propertyFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStr
/*!
\internal
See comment on methodFromReferrerScope: the same applies to property bindings.
+
+If resolver is not null then it is used to resolve the id with which a generalized grouped
+properties starts.
*/
static std::optional<QQmlLSUtilsExpressionType>
propertyBindingFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QString &name,
- QQmlLSUtilsResolveOptions options)
+ QQmlLSUtilsResolveOptions options,
+ QQmlJSTypeResolver *resolverForIds)
{
- if (auto bindings = referrerScope->propertyBindings(name); !bindings.isEmpty()) {
- const auto binding = bindings.front();
+ auto bindings = referrerScope->propertyBindings(name);
+ if (bindings.isEmpty())
+ return {};
+
+ const auto binding = bindings.front();
+
+ if ((binding.bindingType() != QQmlSA::BindingType::AttachedProperty)
+ && (binding.bindingType() != QQmlSA::BindingType::GroupProperty))
+ return {};
+
+ const bool bindingIsAttached = binding.bindingType() == QQmlSA::BindingType::AttachedProperty;
- if ((binding.bindingType() != QQmlSA::BindingType::AttachedProperty) &&
- (binding.bindingType() != QQmlSA::BindingType::GroupProperty))
+ // Generalized grouped properties, like Bindings or PropertyChanges, for example, have bindings
+ // starting in an id (like `someId.someProperty: ...`).
+ // If `someid` is not a property and is a deferred name, then it should be an id.
+ if (!bindingIsAttached && !referrerScope->hasProperty(name)
+ && referrerScope->isNameDeferred(name)) {
+ if (!resolverForIds)
return {};
- const bool bindingIsAttached =
- binding.bindingType() == QQmlSA::BindingType::AttachedProperty;
+ QQmlJSRegisterContent fromId = resolverForIds->scopedType(referrerScope, name);
+ if (fromId.variant() == QQmlJSRegisterContent::ObjectById)
+ return QQmlLSUtilsExpressionType{ name, fromId.type(), QmlObjectIdIdentifier };
- const auto getTypeIdentifier = [&bindingIsAttached, &referrerScope, &name]{
- if (bindingIsAttached)
- return AttachedTypeIdentifier;
+ return QQmlLSUtilsExpressionType{ name, {}, QmlObjectIdIdentifier };
+ }
- // TODO: QTBUG-123618: you can actually have grouped properties on deferred properties
- // that are not id's!
- // If generalized group property, then it is actually an id.
- if (referrerScope->isNameDeferred(name)) {
- return QmlObjectIdIdentifier;
- }
- return GroupedPropertyIdentifier;
- };
+ const auto typeIdentifier =
+ bindingIsAttached ? AttachedTypeIdentifier : GroupedPropertyIdentifier;
- const auto getScope = [&bindingIsAttached, &binding]() -> QQmlJSScope::ConstPtr {
- if (bindingIsAttached)
- return binding.attachingType();
+ const auto getScope = [&bindingIsAttached, &binding]() -> QQmlJSScope::ConstPtr {
+ if (bindingIsAttached)
+ return binding.attachingType();
- return binding.groupType();
- };
+ return binding.groupType();
+ };
- switch (options) {
- case ResolveOwnerType: {
- return QQmlLSUtilsExpressionType{
- name,
- // note: always return the type of the attached type as the owner.
- // Find usages on "Keys.", for example, should yield all usages of the "Keys"
- // attached property.
- bindingIsAttached ? getScope() : findDefiningScopeForProperty(referrerScope, name),
- getTypeIdentifier()
- };
- }
- case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{name, getScope(), getTypeIdentifier()};
- }
+ switch (options) {
+ case ResolveOwnerType: {
+ return QQmlLSUtilsExpressionType{
+ name,
+ // note: always return the type of the attached type as the owner.
+ // Find usages on "Keys.", for example, should yield all usages of the "Keys"
+ // attached property.
+ bindingIsAttached ? getScope() : findDefiningScopeForProperty(referrerScope, name),
+ typeIdentifier
+ };
}
-
- return {};
+ case ResolveActualTypeForFieldMemberExpression:
+ return QQmlLSUtilsExpressionType{ name, getScope(), typeIdentifier };
+ }
+ Q_UNREACHABLE_RETURN({});
}
/*! \internal
@@ -1262,7 +1271,7 @@ resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions
if (auto scope = methodFromReferrerScope(owner->semanticScope, name, options))
return *scope;
- if (auto scope = propertyBindingFromReferrerScope(owner->semanticScope,name, options))
+ if (auto scope = propertyBindingFromReferrerScope(owner->semanticScope, name, options, nullptr))
return *scope;
if (auto scope = propertyFromReferrerScope(owner->semanticScope, name, options))
@@ -1334,18 +1343,18 @@ resolveIdentifierExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions o
if (auto scope = methodFromReferrerScope(referrerScope, name, options))
return scope;
+ const auto resolver = item.containingFile().ownerAs<QmlFile>()->typeResolver();
+ if (!resolver)
+ return {};
+
// check if its found as a property binding
- if (auto scope = propertyBindingFromReferrerScope(referrerScope, name, options))
+ if (auto scope = propertyBindingFromReferrerScope(referrerScope, name, options, resolver.get()))
return *scope;
// check if its an (unqualified) property
if (auto scope = propertyFromReferrerScope(referrerScope, name, options))
return *scope;
- const auto resolver = item.containingFile().ownerAs<QmlFile>()->typeResolver();
- if (!resolver)
- return {};
-
// Returns the baseType, can't use it with options.
if (auto scope = resolver->typeForName(name)) {
if (scope->isSingleton())