diff options
Diffstat (limited to 'src/qmlls')
-rw-r--r-- | src/qmlls/qqmllsutils.cpp | 109 |
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()) |