702 lines
24 KiB
C++
702 lines
24 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2019 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the tools applications of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qqmljsscope_p.h"
|
|
#include "qqmljstypereader_p.h"
|
|
#include "qqmljsimporter_p.h"
|
|
|
|
#include <QtCore/qqueue.h>
|
|
#include <QtCore/qsharedpointer.h>
|
|
#include <QtCore/qfileinfo.h>
|
|
|
|
#include <private/qduplicatetracker_p.h>
|
|
|
|
#include <algorithm>
|
|
#include <type_traits>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
/*! \internal
|
|
|
|
Utility method that returns proper value according to the type To. This
|
|
version returns From.
|
|
*/
|
|
template<typename To, typename From, typename std::enable_if_t<!std::is_pointer_v<To>, int> = 0>
|
|
static auto getQQmlJSScopeFromSmartPtr(const From &p) -> From
|
|
{
|
|
static_assert(!std::is_pointer_v<From>, "From has to be a smart pointer holding QQmlJSScope");
|
|
return p;
|
|
}
|
|
|
|
/*! \internal
|
|
|
|
Utility method that returns proper value according to the type To. This
|
|
version returns From::get(), which is a raw pointer. The returned type is
|
|
not necessary equal to To (e.g. To might be `QQmlJSScope *` while returned
|
|
is `const QQmlJSScope *`).
|
|
*/
|
|
template<typename To, typename From, typename std::enable_if_t<std::is_pointer_v<To>, int> = 0>
|
|
static auto getQQmlJSScopeFromSmartPtr(const From &p) -> decltype(p.get())
|
|
{
|
|
static_assert(!std::is_pointer_v<From>, "From has to be a smart pointer holding QQmlJSScope");
|
|
return p.get();
|
|
}
|
|
|
|
template<typename QQmlJSScopePtr, typename Action>
|
|
static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check)
|
|
{
|
|
// NB: among other things, getQQmlJSScopeFromSmartPtr() also resolves const
|
|
// vs non-const pointer issue, so use it's return value as the type
|
|
using T = decltype(
|
|
getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(std::declval<QQmlJSScope::ConstPtr>()));
|
|
|
|
QDuplicateTracker<T> seen;
|
|
for (T scope = type; scope && !seen.hasSeen(scope);
|
|
scope = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->baseType())) {
|
|
// Extensions override their base types
|
|
for (T extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->extensionType());
|
|
extension && !seen.hasSeen(extension);
|
|
extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(extension->baseType())) {
|
|
if (check(extension))
|
|
return true;
|
|
}
|
|
|
|
if (check(scope))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QQmlJSScope::QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope)
|
|
: m_parentScope(parentScope), m_scopeType(type) {}
|
|
|
|
QQmlJSScope::Ptr QQmlJSScope::create(ScopeType type, const QQmlJSScope::Ptr &parentScope)
|
|
{
|
|
QSharedPointer<QQmlJSScope> childScope(new QQmlJSScope{type, parentScope});
|
|
if (parentScope)
|
|
parentScope->m_childScopes.push_back(childScope);
|
|
return childScope;
|
|
}
|
|
|
|
void QQmlJSScope::insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier)
|
|
{
|
|
Q_ASSERT(m_scopeType != QQmlJSScope::QMLScope);
|
|
if (identifier.kind == JavaScriptIdentifier::LexicalScoped
|
|
|| identifier.kind == JavaScriptIdentifier::Injected
|
|
|| m_scopeType == QQmlJSScope::JSFunctionScope) {
|
|
m_jsIdentifiers.insert(name, identifier);
|
|
} else {
|
|
auto targetScope = parentScope();
|
|
while (targetScope->m_scopeType != QQmlJSScope::JSFunctionScope)
|
|
targetScope = targetScope->parentScope();
|
|
targetScope->m_jsIdentifiers.insert(name, identifier);
|
|
}
|
|
}
|
|
|
|
void QQmlJSScope::insertPropertyIdentifier(const QQmlJSMetaProperty &property)
|
|
{
|
|
addOwnProperty(property);
|
|
QQmlJSMetaMethod method(property.propertyName() + QLatin1String("Changed"), QLatin1String("void"));
|
|
addOwnMethod(method);
|
|
}
|
|
|
|
bool QQmlJSScope::isIdInCurrentScope(const QString &id) const
|
|
{
|
|
return isIdInCurrentQmlScopes(id) || isIdInCurrentJSScopes(id);
|
|
}
|
|
|
|
bool QQmlJSScope::hasMethod(const QString &name) const
|
|
{
|
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
return scope->m_methods.contains(name);
|
|
});
|
|
}
|
|
|
|
QList<QQmlJSMetaMethod> QQmlJSScope::methods(const QString &name) const
|
|
{
|
|
QList<QQmlJSMetaMethod> results;
|
|
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
results.append(scope->ownMethods(name));
|
|
return false;
|
|
});
|
|
return results;
|
|
}
|
|
|
|
bool QQmlJSScope::hasEnumeration(const QString &name) const
|
|
{
|
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
return scope->m_enumerations.contains(name);
|
|
});
|
|
}
|
|
|
|
bool QQmlJSScope::hasEnumerationKey(const QString &name) const
|
|
{
|
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
for (const auto &e : scope->m_enumerations) {
|
|
if (e.keys().contains(name))
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
QQmlJSMetaEnum QQmlJSScope::enumeration(const QString &name) const
|
|
{
|
|
QQmlJSMetaEnum result;
|
|
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
const auto it = scope->m_enumerations.find(name);
|
|
if (it == scope->m_enumerations.end())
|
|
return false;
|
|
result = *it;
|
|
return true;
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
/*!
|
|
Returns if assigning to a property of this type would cause
|
|
implicit component wrapping for non-Component types.
|
|
|
|
\note This method can also be used to check whether a type needs
|
|
to be implicitly wrapped: A type for which this function returns true
|
|
doesn't need to be actually wrapped.
|
|
*/
|
|
bool QQmlJSScope::causesImplicitComponentWrapping() const {
|
|
if (internalName() == u"QQmlComponent")
|
|
return true;
|
|
else if (isComposite()) // composite types are never treated as Component
|
|
return false;
|
|
// A class which is derived from component is not treated as a Component
|
|
// However isUsableComponent considers also QQmlAbstractDelegateComponent
|
|
// See isUsableComponent in qqmltypecompiler.cpp
|
|
|
|
for (auto cppBase = nonCompositeBaseType(baseType()); cppBase; cppBase = cppBase->baseType())
|
|
if (cppBase->internalName() == u"QQmlAbstractDelegateComponent")
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
Returns true if the scope is the outermost element of a separate Component
|
|
Either because it has been implicitly wrapped, e.g. due to an assignment to
|
|
a Component property, or because it is the first (and only) child of a
|
|
Component.
|
|
*/
|
|
bool QQmlJSScope::isComponentRootElement() const {
|
|
if (m_flags.testFlag(WrappedInImplicitComponent))
|
|
return true;
|
|
auto base = nonCompositeBaseType(parentScope()); // handles null parentScope()
|
|
if (!base)
|
|
return false;
|
|
return base->internalName() == u"QQmlComponent";
|
|
}
|
|
|
|
bool QQmlJSScope::isIdInCurrentQmlScopes(const QString &id) const
|
|
{
|
|
if (m_scopeType == QQmlJSScope::QMLScope)
|
|
return m_properties.contains(id) || m_methods.contains(id) || m_enumerations.contains(id);
|
|
|
|
const auto qmlScope = findCurrentQMLScope(parentScope());
|
|
return qmlScope->m_properties.contains(id)
|
|
|| qmlScope->m_methods.contains(id)
|
|
|| qmlScope->m_enumerations.contains(id);
|
|
}
|
|
|
|
bool QQmlJSScope::isIdInCurrentJSScopes(const QString &id) const
|
|
{
|
|
if (m_scopeType != QQmlJSScope::QMLScope && m_jsIdentifiers.contains(id))
|
|
return true;
|
|
|
|
for (auto jsScope = parentScope(); jsScope; jsScope = jsScope->parentScope()) {
|
|
if (jsScope->m_scopeType != QQmlJSScope::QMLScope && jsScope->m_jsIdentifiers.contains(id))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QQmlJSScope::isIdInjectedFromSignal(const QString &id) const
|
|
{
|
|
const auto found = findJSIdentifier(id);
|
|
return found.has_value() && found->kind == JavaScriptIdentifier::Injected;
|
|
}
|
|
|
|
std::optional<QQmlJSScope::JavaScriptIdentifier>
|
|
QQmlJSScope::findJSIdentifier(const QString &id) const
|
|
{
|
|
for (const auto *scope = this; scope; scope = scope->parentScope().data()) {
|
|
if (scope->m_scopeType == QQmlJSScope::JSFunctionScope
|
|
|| scope->m_scopeType == QQmlJSScope::JSLexicalScope) {
|
|
auto it = scope->m_jsIdentifiers.find(id);
|
|
if (it != scope->m_jsIdentifiers.end())
|
|
return *it;
|
|
}
|
|
}
|
|
|
|
return std::optional<JavaScriptIdentifier>{};
|
|
}
|
|
|
|
QQmlJSScope::ConstPtr
|
|
QQmlJSScope::findType(const QString &name,
|
|
const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes)
|
|
{
|
|
auto type = contextualTypes.constFind(name);
|
|
|
|
if (type != contextualTypes.constEnd()) {
|
|
if (usedTypes != nullptr)
|
|
usedTypes->insert(name);
|
|
return *type;
|
|
}
|
|
|
|
const auto colonColon = name.indexOf(QStringLiteral("::"));
|
|
if (colonColon > 0) {
|
|
const QString outerTypeName = name.left(colonColon);
|
|
const auto outerType = contextualTypes.constFind(outerTypeName);
|
|
if (outerType != contextualTypes.constEnd()) {
|
|
for (const auto &innerType : qAsConst((*outerType)->m_childScopes)) {
|
|
if (innerType->m_internalName == name) {
|
|
if (usedTypes != nullptr)
|
|
usedTypes->insert(name);
|
|
return innerType;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return QQmlJSScope::ConstPtr();
|
|
}
|
|
|
|
void QQmlJSScope::resolveType(const QQmlJSScope::Ptr &self,
|
|
const QHash<QString, ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes)
|
|
{
|
|
if (!self->m_baseType && !self->m_baseTypeName.isEmpty())
|
|
self->m_baseType = findType(self->m_baseTypeName, contextualTypes, usedTypes);
|
|
|
|
if (!self->m_attachedType && !self->m_attachedTypeName.isEmpty())
|
|
self->m_attachedType = findType(self->m_attachedTypeName, contextualTypes, usedTypes);
|
|
|
|
if (!self->m_valueType && !self->m_valueTypeName.isEmpty())
|
|
self->m_valueType = findType(self->m_valueTypeName, contextualTypes, usedTypes);
|
|
|
|
if (!self->m_extensionType && !self->m_extensionTypeName.isEmpty())
|
|
self->m_extensionType = findType(self->m_extensionTypeName, contextualTypes, usedTypes);
|
|
|
|
for (auto it = self->m_properties.begin(), end = self->m_properties.end(); it != end; ++it) {
|
|
const QString typeName = it->typeName();
|
|
if (it->type() || typeName.isEmpty())
|
|
continue;
|
|
|
|
if (const auto type = findType(typeName, contextualTypes, usedTypes)) {
|
|
it->setType(type);
|
|
continue;
|
|
}
|
|
|
|
const auto enumeration = self->m_enumerations.find(typeName);
|
|
if (enumeration != self->m_enumerations.end())
|
|
it->setType(enumeration->type());
|
|
}
|
|
|
|
for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
|
|
const QString returnTypeName = it->returnTypeName();
|
|
if (!it->returnType() && !returnTypeName.isEmpty())
|
|
it->setReturnType(findType(returnTypeName, contextualTypes, usedTypes));
|
|
|
|
const auto paramTypeNames = it->parameterTypeNames();
|
|
QList<QSharedPointer<const QQmlJSScope>> paramTypes = it->parameterTypes();
|
|
if (paramTypes.length() < paramTypeNames.length())
|
|
paramTypes.resize(paramTypeNames.length());
|
|
|
|
for (int i = 0, length = paramTypes.length(); i < length; ++i) {
|
|
auto ¶mType = paramTypes[i];
|
|
const auto paramTypeName = paramTypeNames[i];
|
|
if (!paramType && !paramTypeName.isEmpty())
|
|
paramType = findType(paramTypeName, contextualTypes, usedTypes);
|
|
}
|
|
|
|
it->setParameterTypes(paramTypes);
|
|
}
|
|
}
|
|
|
|
void QQmlJSScope::updateChildScope(const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
|
|
const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes)
|
|
{
|
|
switch (childScope->scopeType()) {
|
|
case QQmlJSScope::GroupedPropertyScope:
|
|
searchBaseAndExtensionTypes(self.data(), [&](const QQmlJSScope *type) {
|
|
const auto propertyIt = type->m_properties.find(childScope->internalName());
|
|
if (propertyIt != type->m_properties.end()) {
|
|
childScope->m_baseType = QQmlJSScope::ConstPtr(propertyIt->type());
|
|
childScope->m_baseTypeName = propertyIt->typeName();
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
break;
|
|
case QQmlJSScope::AttachedPropertyScope:
|
|
if (const auto attachedBase =
|
|
findType(childScope->internalName(), contextualTypes, usedTypes)) {
|
|
childScope->m_baseType = attachedBase->attachedType();
|
|
childScope->m_baseTypeName = attachedBase->attachedTypeName();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<typename Resolver, typename ChildScopeUpdater>
|
|
static void resolveTypesInternal(Resolver resolve, ChildScopeUpdater update,
|
|
const QQmlJSScope::Ptr &self,
|
|
const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes)
|
|
{
|
|
resolve(self, contextualTypes, usedTypes);
|
|
// NB: constness ensures no detach
|
|
const QVector<QQmlJSScope::Ptr> childScopes = self->childScopes();
|
|
for (auto it = childScopes.begin(), end = childScopes.end(); it != end; ++it) {
|
|
const QQmlJSScope::Ptr childScope = *it;
|
|
update(childScope, self, contextualTypes, usedTypes);
|
|
resolveTypesInternal(resolve, update, childScope, contextualTypes, usedTypes); // recursion
|
|
}
|
|
}
|
|
|
|
void QQmlJSScope::resolveTypes(const QQmlJSScope::Ptr &self,
|
|
const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes)
|
|
{
|
|
const auto resolveAll = [](const QQmlJSScope::Ptr &self,
|
|
const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes) {
|
|
resolveEnums(self, contextualTypes, usedTypes);
|
|
resolveType(self, contextualTypes, usedTypes);
|
|
};
|
|
resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
|
|
}
|
|
|
|
void QQmlJSScope::resolveNonEnumTypes(const QQmlJSScope::Ptr &self,
|
|
const QHash<QString, ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes)
|
|
{
|
|
resolveTypesInternal(resolveType, updateChildScope, self, contextualTypes, usedTypes);
|
|
}
|
|
|
|
void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self,
|
|
const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes)
|
|
{
|
|
const auto intType = findType(QStringLiteral("int"), contextualTypes, usedTypes);
|
|
Q_ASSERT(intType); // There always has to be a builtin "int" type
|
|
for (auto it = self->m_enumerations.begin(), end = self->m_enumerations.end(); it != end;
|
|
++it) {
|
|
if (it->type())
|
|
continue;
|
|
auto enumScope = QQmlJSScope::create(EnumScope, self);
|
|
enumScope->m_baseTypeName = QStringLiteral("int");
|
|
enumScope->m_baseType = intType;
|
|
enumScope->m_semantics = AccessSemantics::Value;
|
|
enumScope->m_internalName = self->internalName() + QStringLiteral("::") + it->name();
|
|
it->setType(ConstPtr(enumScope));
|
|
}
|
|
}
|
|
|
|
void QQmlJSScope::resolveGeneralizedGroup(const Ptr &self, const ConstPtr &baseType,
|
|
const QHash<QString, ConstPtr> &contextualTypes,
|
|
QSet<QString> *usedTypes)
|
|
{
|
|
self->m_baseType = baseType;
|
|
resolveNonEnumTypes(self, contextualTypes, usedTypes);
|
|
}
|
|
|
|
QQmlJSScope::ConstPtr QQmlJSScope::findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope)
|
|
{
|
|
auto qmlScope = scope;
|
|
while (qmlScope && qmlScope->m_scopeType != QQmlJSScope::QMLScope)
|
|
qmlScope = qmlScope->parentScope();
|
|
return qmlScope;
|
|
}
|
|
|
|
void QQmlJSScope::addExport(const QString &name, const QString &package,
|
|
const QTypeRevision &version)
|
|
{
|
|
m_exports.append(Export(package, name, version));
|
|
}
|
|
|
|
bool QQmlJSScope::hasProperty(const QString &name) const
|
|
{
|
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
return scope->m_properties.contains(name);
|
|
});
|
|
}
|
|
|
|
QQmlJSMetaProperty QQmlJSScope::property(const QString &name) const
|
|
{
|
|
QQmlJSMetaProperty prop;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
const auto it = scope->m_properties.find(name);
|
|
if (it == scope->m_properties.end())
|
|
return false;
|
|
prop = *it;
|
|
return true;
|
|
});
|
|
return prop;
|
|
}
|
|
|
|
QQmlJSScope::ConstPtr QQmlJSScope::ownerOfProperty(const QQmlJSScope::ConstPtr &self,
|
|
const QString &name)
|
|
{
|
|
QQmlJSScope::ConstPtr owner;
|
|
searchBaseAndExtensionTypes(self, [&](const QQmlJSScope::ConstPtr &scope) {
|
|
if (scope->hasOwnProperty(name)) {
|
|
owner = scope;
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
return owner;
|
|
}
|
|
|
|
void QQmlJSScope::setPropertyLocallyRequired(const QString &name, bool isRequired)
|
|
{
|
|
if (!isRequired)
|
|
m_requiredPropertyNames.removeOne(name);
|
|
else if (!m_requiredPropertyNames.contains(name))
|
|
m_requiredPropertyNames.append(name);
|
|
}
|
|
|
|
bool QQmlJSScope::isPropertyRequired(const QString &name) const
|
|
{
|
|
bool isRequired = false;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
if (scope->isPropertyLocallyRequired(name)) {
|
|
isRequired = true;
|
|
return true;
|
|
}
|
|
|
|
// If it has a property of that name, and that is not required, then none of the
|
|
// base types matter. You cannot make a derived type's property required with
|
|
// a "required" specification in a base type.
|
|
return scope->hasOwnProperty(name);
|
|
});
|
|
return isRequired;
|
|
}
|
|
|
|
bool QQmlJSScope::isPropertyLocallyRequired(const QString &name) const
|
|
{
|
|
return m_requiredPropertyNames.contains(name);
|
|
}
|
|
|
|
bool QQmlJSScope::hasPropertyBinding(const QString &name) const
|
|
{
|
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
return scope->m_propertyBindings.contains(name);
|
|
});
|
|
}
|
|
|
|
QQmlJSMetaPropertyBinding QQmlJSScope::propertyBinding(const QString &name) const
|
|
{
|
|
QQmlJSMetaPropertyBinding binding;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
const auto it = scope->m_propertyBindings.find(name);
|
|
if (it == scope->m_propertyBindings.end())
|
|
return false;
|
|
binding = *it;
|
|
return true;
|
|
});
|
|
return binding;
|
|
}
|
|
|
|
QList<QQmlJSMetaPropertyBinding> QQmlJSScope::propertyBindings(const QString &name) const
|
|
{
|
|
QList<QQmlJSMetaPropertyBinding> bindings;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
const auto range = scope->m_propertyBindings.equal_range(name);
|
|
for (auto it = range.first; it != range.second; ++it)
|
|
bindings.append(*it);
|
|
return false;
|
|
});
|
|
return bindings;
|
|
}
|
|
|
|
bool QQmlJSScope::hasInterface(const QString &name) const
|
|
{
|
|
return searchBaseAndExtensionTypes(
|
|
this, [&](const QQmlJSScope *scope) { return scope->m_interfaceNames.contains(name); });
|
|
}
|
|
|
|
bool QQmlJSScope::isNameDeferred(const QString &name) const
|
|
{
|
|
bool isDeferred = false;
|
|
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
const QStringList immediate = scope->ownImmediateNames();
|
|
if (!immediate.isEmpty()) {
|
|
isDeferred = !immediate.contains(name);
|
|
return true;
|
|
}
|
|
|
|
const QStringList deferred = scope->ownDeferredNames();
|
|
if (!deferred.isEmpty()) {
|
|
isDeferred = deferred.contains(name);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
return isDeferred;
|
|
}
|
|
|
|
QString QQmlJSScope::attachedTypeName() const
|
|
{
|
|
QString name;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
if (scope->ownAttachedType().isNull())
|
|
return false;
|
|
name = scope->ownAttachedTypeName();
|
|
return true;
|
|
});
|
|
|
|
return name;
|
|
}
|
|
|
|
QQmlJSScope::ConstPtr QQmlJSScope::attachedType() const
|
|
{
|
|
QQmlJSScope::ConstPtr ptr;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
if (scope->ownAttachedType().isNull())
|
|
return false;
|
|
ptr = scope->ownAttachedType();
|
|
return true;
|
|
});
|
|
|
|
return ptr;
|
|
}
|
|
|
|
bool QQmlJSScope::isResolved() const
|
|
{
|
|
if (m_scopeType == ScopeType::AttachedPropertyScope
|
|
|| m_scopeType == ScopeType::GroupedPropertyScope) {
|
|
return m_internalName.isEmpty() || !m_baseType.isNull();
|
|
}
|
|
|
|
return m_baseTypeName.isEmpty() || !m_baseType.isNull();
|
|
}
|
|
|
|
QString QQmlJSScope::defaultPropertyName() const
|
|
{
|
|
QString name;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
name = scope->ownDefaultPropertyName();
|
|
return !name.isEmpty();
|
|
});
|
|
return name;
|
|
}
|
|
|
|
QString QQmlJSScope::parentPropertyName() const
|
|
{
|
|
QString name;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
name = scope->ownParentPropertyName();
|
|
return !name.isEmpty();
|
|
});
|
|
return name;
|
|
}
|
|
|
|
bool QQmlJSScope::isFullyResolved() const
|
|
{
|
|
bool baseResolved = true;
|
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
|
if (!scope->isResolved()) {
|
|
baseResolved = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
return baseResolved;
|
|
}
|
|
|
|
QQmlJSScope::Export::Export(QString package, QString type, const QTypeRevision &version) :
|
|
m_package(std::move(package)),
|
|
m_type(std::move(type)),
|
|
m_version(version)
|
|
{
|
|
}
|
|
|
|
bool QQmlJSScope::Export::isValid() const
|
|
{
|
|
return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
|
|
}
|
|
|
|
QQmlJSScope QDeferredFactory<QQmlJSScope>::create() const
|
|
{
|
|
QQmlJSTypeReader typeReader(m_importer, m_filePath);
|
|
QQmlJSScope::Ptr result = typeReader();
|
|
m_importer->m_warnings.append(typeReader.errors());
|
|
result->setInternalName(QFileInfo(m_filePath).baseName());
|
|
return std::move(*result);
|
|
}
|
|
|
|
bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
|
|
{
|
|
if (!derived)
|
|
return false;
|
|
|
|
bool isBaseComponent = causesImplicitComponentWrapping();
|
|
|
|
QDuplicateTracker<QQmlJSScope::ConstPtr> seen;
|
|
for (auto scope = derived; !scope.isNull() && !seen.hasSeen(scope); scope = scope->baseType()) {
|
|
if (isSameType(scope))
|
|
return true;
|
|
if (isBaseComponent && scope->internalName() == u"QObject"_qs)
|
|
return true;
|
|
}
|
|
|
|
return internalName() == u"QVariant"_qs || internalName() == u"QJSValue"_qs;
|
|
}
|
|
|
|
bool QQmlJSScope::isInCustomParserParent() const
|
|
{
|
|
for (const auto *scope = this; scope; scope = scope->parentScope().get()) {
|
|
if (!scope->baseType().isNull() && scope->baseType()->hasCustomParser())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QT_END_NAMESPACE
|