QmlCompiler: Allow lists as arguments to methods
Since lists are allowed as property types, you should be able to pass them as arguments to methods, too. For now we only handle QML-defined methods, implemented by adding JavaScript functions to your QML elements. The usual type coercion rules apply if you pass JavaScript arrays to such methods. That is, it usually works. We now resolve properties with the "list" flag to their actual types (QQmlListProperty or QList) already when populating the QQmlJSScope, and store the list types as members of QQmlJSScope rather than as a special map in QQmlJSTypeResolver. This allows us to do the same to lists passed as arguments and simplifies some of the type analysis. Fixes: QTBUG-107171 Change-Id: Idf71ccdc1d59f472c17084a36b5d7879c4d959c0 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
42065c0e6e
commit
91c6d45559
|
@ -153,6 +153,20 @@ Module {
|
|||
Signal { name: "destruction" }
|
||||
}
|
||||
|
||||
Component {
|
||||
file: "qqmllist.h"
|
||||
name: "QQmlListProperty<QObject>"
|
||||
accessSemantics: "sequence"
|
||||
valueType: "QObject"
|
||||
}
|
||||
|
||||
Component {
|
||||
file: "qobject.h"
|
||||
name: "QObjectList"
|
||||
accessSemantics: "sequence"
|
||||
valueType: "QObject"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "int"
|
||||
extension: "Number"
|
||||
|
|
|
@ -1794,9 +1794,21 @@ void QQmlJSCodeGenerator::generate_DefineArray(int argc, int args)
|
|||
registerVariable(args + i));
|
||||
}
|
||||
|
||||
m_body += m_state.accumulatorVariableOut + u" = "_s + stored->internalName() + u'{';
|
||||
m_body += initializer.join(u", "_s);
|
||||
m_body += u"};\n";
|
||||
if (stored->isListProperty()) {
|
||||
reject(u"creating a QQmlListProperty not backed by a property"_s);
|
||||
|
||||
// We can, technically, generate code for this. But it's dangerous:
|
||||
//
|
||||
// const QString storage = m_state.accumulatorVariableOut + u"_storage"_s;
|
||||
// m_body += stored->internalName() + u"::ListType " + storage
|
||||
// + u" = {"_s + initializer.join(u", "_s) + u"};\n"_s;
|
||||
// m_body += m_state.accumulatorVariableOut
|
||||
// + u" = " + stored->internalName() + u"(nullptr, &"_s + storage + u");\n"_s;
|
||||
} else {
|
||||
m_body += m_state.accumulatorVariableOut + u" = "_s + stored->internalName() + u'{';
|
||||
m_body += initializer.join(u", "_s);
|
||||
m_body += u"};\n";
|
||||
}
|
||||
}
|
||||
|
||||
void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int argc, int args)
|
||||
|
@ -1994,6 +2006,9 @@ QString QQmlJSCodeGenerator::contentPointer(const QQmlJSRegisterContent &content
|
|||
return u'&' + var;
|
||||
}
|
||||
|
||||
if (stored->isListProperty() && m_typeResolver->containedType(content)->isListProperty())
|
||||
return u'&' + var;
|
||||
|
||||
reject(u"content pointer of non-QVariant wrapper type "_s + content.descriptiveName());
|
||||
return QString();
|
||||
}
|
||||
|
@ -2017,6 +2032,9 @@ QString QQmlJSCodeGenerator::contentType(const QQmlJSRegisterContent &content, c
|
|||
return metaTypeFromType(m_typeResolver->intType());
|
||||
}
|
||||
|
||||
if (stored->isListProperty() && m_typeResolver->containedType(content)->isListProperty())
|
||||
return metaTypeFromType(m_typeResolver->listPropertyType());
|
||||
|
||||
reject(u"content type of non-QVariant wrapper type "_s + content.descriptiveName());
|
||||
return QString();
|
||||
}
|
||||
|
|
|
@ -746,6 +746,7 @@ QQmlJSAotFunction QQmlJSAotCompiler::globalCode() const
|
|||
u"QtQml/qqmlcomponent.h"_s,
|
||||
u"QtQml/qqmlcontext.h"_s,
|
||||
u"QtQml/qqmlengine.h"_s,
|
||||
u"QtQml/qqmllist.h"_s,
|
||||
|
||||
u"QtCore/qdatetime.h"_s,
|
||||
u"QtCore/qobject.h"_s,
|
||||
|
|
|
@ -206,12 +206,11 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run(
|
|||
}
|
||||
|
||||
const auto property = m_objectType->property(propertyName);
|
||||
function.returnType = property.isList()
|
||||
? m_typeResolver->listType(property.type(), QQmlJSTypeResolver::UseQObjectList)
|
||||
: QQmlJSScope::ConstPtr(property.type());
|
||||
|
||||
|
||||
if (!function.returnType) {
|
||||
if (const QQmlJSScope::ConstPtr propertyType = property.type()) {
|
||||
function.returnType = propertyType->isListProperty()
|
||||
? m_typeResolver->qObjectListType()
|
||||
: propertyType;
|
||||
} else {
|
||||
diagnose(u"Cannot resolve property type %1 for binding on %2"_s.arg(
|
||||
property.typeName(), propertyName),
|
||||
QtWarningMsg, bindingLocation, error);
|
||||
|
|
|
@ -462,9 +462,12 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
|
|||
// resolve enumerations (which can potentially create new child scopes)
|
||||
// before resolving the type fully
|
||||
const QQmlJSScope::ConstPtr intType = tempTypes.cppNames.type(u"int"_s).scope;
|
||||
const QQmlJSScope::ConstPtr arrayType = tempTypes.cppNames.type(u"Array"_s).scope;
|
||||
for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
|
||||
if (!it->scope.factory())
|
||||
if (!it->scope.factory()) {
|
||||
QQmlJSScope::resolveEnums(it->scope, intType);
|
||||
QQmlJSScope::resolveList(it->scope, arrayType);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
|
||||
|
|
|
@ -558,7 +558,9 @@ void QQmlJSImportVisitor::processDefaultProperties()
|
|||
|
||||
const QQmlJSMetaProperty defaultProp = parentScope->property(defaultPropertyName);
|
||||
|
||||
if (it.value().size() > 1 && !defaultProp.isList()) {
|
||||
if (it.value().size() > 1
|
||||
&& !defaultProp.isList()
|
||||
&& !defaultProp.type()->isListProperty()) {
|
||||
m_logger->log(
|
||||
QStringLiteral("Cannot assign multiple objects to a default non-list property"),
|
||||
qmlNonListProperty, it.value().constFirst()->sourceLocation());
|
||||
|
@ -1477,7 +1479,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
|
|||
const auto type =
|
||||
isAlias ? QQmlJSScope::ConstPtr() : m_rootScopeImports.type(typeName).scope;
|
||||
if (type) {
|
||||
prop.setType(type);
|
||||
prop.setType(prop.isList() ? type->listType() : type);
|
||||
const QString internalName = type->internalName();
|
||||
prop.setTypeName(internalName.isEmpty() ? typeName : internalName);
|
||||
} else if (!isAlias) {
|
||||
|
|
|
@ -63,11 +63,9 @@ bool QQmlJSRegisterContent::isList() const
|
|||
case Type:
|
||||
return std::get<QQmlJSScope::ConstPtr>(m_content)->accessSemantics()
|
||||
== QQmlJSScope::AccessSemantics::Sequence;
|
||||
case Property: {
|
||||
const auto prop = std::get<QQmlJSMetaProperty>(m_content);
|
||||
return prop.isList()
|
||||
|| prop.type()->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence;
|
||||
}
|
||||
case Property:
|
||||
return std::get<QQmlJSMetaProperty>(m_content).type()->accessSemantics()
|
||||
== QQmlJSScope::AccessSemantics::Sequence;
|
||||
case Conversion:
|
||||
return std::get<ConvertedTypes>(m_content).result->accessSemantics()
|
||||
== QQmlJSScope::AccessSemantics::Sequence;
|
||||
|
|
|
@ -379,8 +379,35 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
|
|||
return *type;
|
||||
}
|
||||
|
||||
const auto findListType = [&](const QString &prefix, const QString &postfix)
|
||||
-> ImportedScope<ConstPtr> {
|
||||
if (name.startsWith(prefix) && name.endsWith(postfix)) {
|
||||
const qsizetype prefixLength = prefix.length();
|
||||
const QString &elementName
|
||||
= name.mid(prefixLength, name.length() - prefixLength - postfix.length());
|
||||
const ImportedScope<ConstPtr> element
|
||||
= findType(elementName, contextualTypes, usedTypes);
|
||||
if (element.scope) {
|
||||
useType();
|
||||
return { element.scope->listType(), element.revision };
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
switch (contextualTypes.context()) {
|
||||
case ContextualTypes::INTERNAL: {
|
||||
if (const auto listType = findListType(u"QList<"_s, u">"_s);
|
||||
listType.scope && !listType.scope->isReferenceType()) {
|
||||
return listType;
|
||||
}
|
||||
|
||||
if (const auto listType = findListType(u"QQmlListProperty<"_s, u">"_s);
|
||||
listType.scope && listType.scope->isReferenceType()) {
|
||||
return listType;
|
||||
}
|
||||
|
||||
// look for c++ namescoped enums!
|
||||
const auto colonColon = name.lastIndexOf(QStringLiteral("::"));
|
||||
if (colonColon == -1)
|
||||
|
@ -407,6 +434,10 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
|
|||
useType();
|
||||
return inlineComponent;
|
||||
}
|
||||
|
||||
if (const auto listType = findListType(u"list<"_s, u">"_s); listType.scope)
|
||||
return listType;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -417,6 +448,11 @@ QTypeRevision QQmlJSScope::resolveType(
|
|||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &context,
|
||||
QSet<QString> *usedTypes)
|
||||
{
|
||||
if (self->accessSemantics() == AccessSemantics::Sequence
|
||||
&& self->internalName().startsWith(u"QQmlListProperty<"_s)) {
|
||||
self->setIsListProperty(true);
|
||||
}
|
||||
|
||||
const QString baseTypeName = self->baseTypeName();
|
||||
const auto baseType = findType(baseTypeName, context, usedTypes);
|
||||
if (!self->m_baseType.scope && !baseTypeName.isEmpty())
|
||||
|
@ -447,13 +483,16 @@ QTypeRevision QQmlJSScope::resolveType(
|
|||
continue;
|
||||
|
||||
if (const auto type = findType(typeName, context, usedTypes); type.scope) {
|
||||
it->setType(type.scope);
|
||||
it->setType(it->isList() ? type.scope->listType() : type.scope);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto enumeration = self->m_enumerations.find(typeName);
|
||||
if (enumeration != self->m_enumerations.end())
|
||||
it->setType(enumeration->type());
|
||||
if (enumeration != self->m_enumerations.end()) {
|
||||
it->setType(it->isList()
|
||||
? enumeration->type()->listType()
|
||||
: QQmlJSScope::ConstPtr(enumeration->type()));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
|
||||
|
@ -540,6 +579,7 @@ QTypeRevision QQmlJSScope::resolveTypes(
|
|||
const QQmlJSScope::ContextualTypes &contextualTypes,
|
||||
QSet<QString> *usedTypes) {
|
||||
resolveEnums(self, contextualTypes.intType());
|
||||
resolveList(self, contextualTypes.arrayType());
|
||||
return resolveType(self, contextualTypes, usedTypes);
|
||||
};
|
||||
return resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
|
||||
|
@ -570,6 +610,40 @@ void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::
|
|||
}
|
||||
}
|
||||
|
||||
void QQmlJSScope::resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType)
|
||||
{
|
||||
if (self->listType() || self->accessSemantics() == AccessSemantics::Sequence)
|
||||
return;
|
||||
|
||||
Q_ASSERT(!arrayType.isNull());
|
||||
QQmlJSScope::Ptr listType = QQmlJSScope::create();
|
||||
listType->setAccessSemantics(AccessSemantics::Sequence);
|
||||
listType->setValueTypeName(self->internalName());
|
||||
|
||||
if (self->isComposite()) {
|
||||
// There is no internalName for this thing. Just set the value type right away
|
||||
listType->setInternalName(u"QQmlListProperty<>"_s);
|
||||
listType->m_valueType = QQmlJSScope::ConstPtr(self);
|
||||
} else if (self->isReferenceType()) {
|
||||
listType->setInternalName(u"QQmlListProperty<%2>"_s.arg(self->internalName()));
|
||||
// Do not set a filePath on the list type, so that we have to generalize it
|
||||
// even in direct mode.
|
||||
} else {
|
||||
listType->setInternalName(u"QList<%2>"_s.arg(self->internalName()));
|
||||
listType->setFilePath(self->filePath());
|
||||
}
|
||||
|
||||
const QQmlJSImportedScope element = {self, QTypeRevision()};
|
||||
const QQmlJSImportedScope array = {arrayType, QTypeRevision()};
|
||||
QQmlJSScope::ContextualTypes contextualTypes(
|
||||
QQmlJSScope::ContextualTypes::INTERNAL, { { self->internalName(), element }, },
|
||||
QQmlJSScope::ConstPtr(), arrayType);
|
||||
QQmlJSScope::resolveTypes(listType, contextualTypes);
|
||||
|
||||
Q_ASSERT(listType->valueType() == self);
|
||||
self->m_listType = listType;
|
||||
}
|
||||
|
||||
void QQmlJSScope::resolveGeneralizedGroup(
|
||||
const Ptr &self, const ConstPtr &baseType,
|
||||
const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
|
||||
|
@ -1003,6 +1077,7 @@ void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &
|
|||
m_importer->m_globalWarnings.append(typeReader.errors());
|
||||
scope->setInternalName(internalName());
|
||||
QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames().intType());
|
||||
QQmlJSScope::resolveList(scope, m_importer->builtinInternalNames().arrayType());
|
||||
|
||||
if (m_isSingleton && !scope->isSingleton()) {
|
||||
m_importer->m_globalWarnings.append(
|
||||
|
@ -1054,7 +1129,10 @@ bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
|
|||
return true;
|
||||
}
|
||||
|
||||
return internalName() == u"QVariant"_s || internalName() == u"QJSValue"_s;
|
||||
if (internalName() == u"QVariant"_s || internalName() == u"QJSValue"_s)
|
||||
return true;
|
||||
|
||||
return isListProperty() && valueType()->canAssign(derived);
|
||||
}
|
||||
|
||||
bool QQmlJSScope::isInCustomParserParent() const
|
||||
|
|
|
@ -81,6 +81,7 @@ public:
|
|||
WrappedInImplicitComponent = 0x80,
|
||||
HasBaseTypeError = 0x100,
|
||||
HasExtensionNamespace = 0x200,
|
||||
IsListProperty = 0x400,
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
Q_FLAGS(Flags);
|
||||
|
@ -490,6 +491,8 @@ public:
|
|||
QString valueTypeName() const { return m_valueTypeName; }
|
||||
void setValueTypeName(const QString &name) { m_valueTypeName = name; }
|
||||
QQmlJSScope::ConstPtr valueType() const { return m_valueType; }
|
||||
QQmlJSScope::ConstPtr listType() const { return m_listType; }
|
||||
QQmlJSScope::Ptr listType() { return m_listType; }
|
||||
|
||||
void addOwnRuntimeFunctionIndex(QQmlJSMetaMethod::AbsoluteFunctionIndex index)
|
||||
{
|
||||
|
@ -531,6 +534,9 @@ public:
|
|||
void setIsWrappedInImplicitComponent(bool v) { m_flags.setFlag(WrappedInImplicitComponent, v); }
|
||||
void setExtensionIsNamespace(bool v) { m_flags.setFlag(HasExtensionNamespace, v); }
|
||||
|
||||
bool isListProperty() const { return m_flags.testFlag(IsListProperty); }
|
||||
void setIsListProperty(bool v) { m_flags.setFlag(IsListProperty, v); }
|
||||
|
||||
void setAccessSemantics(AccessSemantics semantics) { m_semantics = semantics; }
|
||||
AccessSemantics accessSemantics() const { return m_semantics; }
|
||||
bool isReferenceType() const { return m_semantics == QQmlJSScope::AccessSemantics::Reference; }
|
||||
|
@ -574,6 +580,8 @@ public:
|
|||
QSet<QString> *usedTypes = nullptr);
|
||||
static void resolveEnums(
|
||||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &intType);
|
||||
static void resolveList(
|
||||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType);
|
||||
static void resolveGeneralizedGroup(
|
||||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &baseType,
|
||||
const QQmlJSScope::ContextualTypes &contextualTypes,
|
||||
|
@ -738,6 +746,7 @@ private:
|
|||
*/
|
||||
QString m_valueTypeName;
|
||||
QQmlJSScope::WeakConstPtr m_valueType;
|
||||
QQmlJSScope::Ptr m_listType;
|
||||
|
||||
/*!
|
||||
The extension is provided as either a type (QML_{NAMESPACE_}EXTENDED) or as a
|
||||
|
|
|
@ -43,8 +43,10 @@ QQmlJSCompilePass::InstructionAnnotations QQmlJSStorageGeneralizer::run(
|
|||
|
||||
const auto transformRegisters
|
||||
= [&](QFlatMap<int, QQmlJSRegisterContent> ®isters) {
|
||||
for (auto j = registers.begin(), jEnd = registers.end(); j != jEnd; ++j)
|
||||
transformRegister(j.value());
|
||||
for (auto j = registers.begin(), jEnd = registers.end(); j != jEnd; ++j) {
|
||||
QQmlJSRegisterContent &content = j.value();
|
||||
transformRegister(content);
|
||||
}
|
||||
};
|
||||
|
||||
for (QQmlJSRegisterContent &argument : function->argumentTypes) {
|
||||
|
|
|
@ -21,7 +21,7 @@ Q_LOGGING_CATEGORY(lcTypeResolver, "qt.qml.compiler.typeresolver", QtInfoMsg);
|
|||
|
||||
QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
|
||||
: m_imports(importer->builtinInternalNames())
|
||||
, m_typeTracker(std::make_unique<TypeTracker>())
|
||||
, m_trackedTypes(std::make_unique<QHash<QQmlJSScope::ConstPtr, TrackedType>>())
|
||||
{
|
||||
const QQmlJSImporter::ImportedTypes &builtinTypes = m_imports;
|
||||
m_voidType = builtinTypes.type(u"void"_s).scope;
|
||||
|
@ -39,6 +39,8 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
|
|||
m_variantListType = builtinTypes.type(u"QVariantList"_s).scope;
|
||||
m_varType = builtinTypes.type(u"QVariant"_s).scope;
|
||||
m_jsValueType = builtinTypes.type(u"QJSValue"_s).scope;
|
||||
m_listPropertyType = builtinTypes.type(u"QQmlListProperty<QObject>"_s).scope;
|
||||
m_qObjectListType = builtinTypes.type(u"QObjectList"_s).scope;
|
||||
|
||||
QQmlJSScope::Ptr emptyListType = QQmlJSScope::create();
|
||||
emptyListType->setInternalName(u"void*"_s);
|
||||
|
@ -53,15 +55,6 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
|
|||
jsPrimitiveType->setAccessSemantics(QQmlJSScope::AccessSemantics::Value);
|
||||
m_jsPrimitiveType = jsPrimitiveType;
|
||||
|
||||
QQmlJSScope::Ptr listPropertyType = QQmlJSScope::create();
|
||||
listPropertyType->setInternalName(u"QQmlListProperty<QObject>"_s);
|
||||
listPropertyType->setFilePath(u"qqmllist.h"_s);
|
||||
listPropertyType->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
|
||||
listPropertyType->setValueTypeName(u"QObject"_s);
|
||||
QQmlJSScope::resolveTypes(listPropertyType, builtinTypes);
|
||||
Q_ASSERT(!listPropertyType->extensionType().scope.isNull());
|
||||
m_listPropertyType = listPropertyType;
|
||||
|
||||
QQmlJSScope::Ptr metaObjectType = QQmlJSScope::create();
|
||||
metaObjectType->setInternalName(u"const QMetaObject"_s);
|
||||
metaObjectType->setFilePath(u"qmetaobject.h"_s);
|
||||
|
@ -126,49 +119,18 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::scopeForId(
|
|||
return m_objectsById.scope(id, referrer);
|
||||
}
|
||||
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::listType(
|
||||
const QQmlJSScope::ConstPtr &elementType, ListMode mode) const
|
||||
{
|
||||
if (elementType.isNull())
|
||||
return QQmlJSScope::ConstPtr();
|
||||
|
||||
auto it = m_typeTracker->listTypes.find(elementType);
|
||||
if (it != m_typeTracker->listTypes.end())
|
||||
return *it;
|
||||
|
||||
switch (elementType->accessSemantics()) {
|
||||
case QQmlJSScope::AccessSemantics::Reference:
|
||||
if (mode == UseListReference)
|
||||
return m_listPropertyType;
|
||||
if (elementType->internalName() != u"QObject"_s)
|
||||
return listType(genericType(elementType), mode);
|
||||
Q_FALLTHROUGH();
|
||||
case QQmlJSScope::AccessSemantics::Value: {
|
||||
QQmlJSScope::Ptr listType = QQmlJSScope::create();
|
||||
listType->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
|
||||
listType->setValueTypeName(elementType->internalName());
|
||||
listType->setInternalName(u"QList<%1>"_s.arg(elementType->augmentedInternalName()));
|
||||
listType->setFilePath(elementType->filePath());
|
||||
const QQmlJSImportedScope element = {elementType, QTypeRevision()};
|
||||
const QQmlJSImportedScope array = {m_arrayType, QTypeRevision()};
|
||||
QQmlJSScope::ContextualTypes contextualTypes(
|
||||
QQmlJSScope::ContextualTypes::INTERNAL,
|
||||
{ { elementType->internalName(), element } },
|
||||
m_intType, m_arrayType);
|
||||
QQmlJSScope::resolveTypes(listType, contextualTypes);
|
||||
Q_ASSERT(equals(listType->valueType(), elementType));
|
||||
m_typeTracker->listTypes[elementType] = listType;
|
||||
return listType;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QQmlJSScope::ConstPtr();
|
||||
}
|
||||
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::typeFromAST(QQmlJS::AST::Type *type) const
|
||||
{
|
||||
return m_imports.type(QmlIR::IRBuilder::asString(type->typeId)).scope;
|
||||
const QString typeId = QmlIR::IRBuilder::asString(type->typeId);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||
if (!type->typeArgument)
|
||||
return m_imports.type(typeId).scope;
|
||||
if (typeId == u"list"_s)
|
||||
return typeForName(type->typeArgument->toString())->listType();
|
||||
return QQmlJSScope::ConstPtr();
|
||||
#else
|
||||
return m_imports.type(typeId).scope;
|
||||
#endif
|
||||
}
|
||||
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::typeForConst(QV4::ReturnedValue rv) const
|
||||
|
@ -309,12 +271,8 @@ QQmlJSTypeResolver::containedType(const QQmlJSRegisterContent &container) const
|
|||
{
|
||||
if (container.isType())
|
||||
return container.type();
|
||||
if (container.isProperty()) {
|
||||
const QQmlJSMetaProperty prop = container.property();
|
||||
return prop.isList()
|
||||
? listType(prop.type(), UseListReference)
|
||||
: QQmlJSScope::ConstPtr(prop.type());
|
||||
}
|
||||
if (container.isProperty())
|
||||
return container.property().type();
|
||||
if (container.isEnumeration())
|
||||
return container.enumeration().type();
|
||||
if (container.isMethod())
|
||||
|
@ -335,33 +293,17 @@ QQmlJSTypeResolver::containedType(const QQmlJSRegisterContent &container) const
|
|||
Q_UNREACHABLE_RETURN({});
|
||||
}
|
||||
|
||||
void QQmlJSTypeResolver::trackListPropertyType(
|
||||
const QQmlJSScope::ConstPtr &trackedListElementType) const
|
||||
{
|
||||
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
|
||||
return;
|
||||
|
||||
if (m_typeTracker->trackedTypes.contains(trackedListElementType)
|
||||
&& !m_typeTracker->listTypes.contains(trackedListElementType)) {
|
||||
const QQmlJSScope::ConstPtr list = listType(
|
||||
comparableType(trackedListElementType), UseListReference);
|
||||
QQmlJSScope::Ptr clone = QQmlJSScope::clone(list);
|
||||
m_typeTracker->listTypes[trackedListElementType] = clone;
|
||||
m_typeTracker->trackedTypes[clone] = { list, QQmlJSScope::ConstPtr(), clone };
|
||||
}
|
||||
}
|
||||
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::trackedType(const QQmlJSScope::ConstPtr &type) const
|
||||
{
|
||||
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
|
||||
return type;
|
||||
|
||||
// If origin is in fact an already tracked type, track the original of that one instead.
|
||||
const auto it = m_typeTracker->trackedTypes.find(type);
|
||||
QQmlJSScope::ConstPtr orig = (it == m_typeTracker->trackedTypes.end()) ? type : it->original;
|
||||
const auto it = m_trackedTypes->find(type);
|
||||
QQmlJSScope::ConstPtr orig = (it == m_trackedTypes->end()) ? type : it->original;
|
||||
|
||||
QQmlJSScope::Ptr clone = QQmlJSScope::clone(orig);
|
||||
m_typeTracker->trackedTypes[clone] = { std::move(orig), QQmlJSScope::ConstPtr(), clone };
|
||||
m_trackedTypes->insert(clone, { std::move(orig), QQmlJSScope::ConstPtr(), clone });
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
@ -378,8 +320,6 @@ QQmlJSRegisterContent QQmlJSTypeResolver::transformed(
|
|||
if (origin.isProperty()) {
|
||||
QQmlJSMetaProperty prop = origin.property();
|
||||
prop.setType((this->*op)(prop.type()));
|
||||
if (prop.isList())
|
||||
trackListPropertyType(prop.type());
|
||||
return QQmlJSRegisterContent::create(
|
||||
(this->*op)(origin.storedType()), prop,
|
||||
origin.variant(), (this->*op)(origin.scopeType()));
|
||||
|
@ -487,7 +427,7 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::trackedContainedType(
|
|||
const QQmlJSRegisterContent &container) const
|
||||
{
|
||||
const QQmlJSScope::ConstPtr type = containedType(container);
|
||||
return m_typeTracker->trackedTypes.contains(type) ? type : QQmlJSScope::ConstPtr();
|
||||
return m_trackedTypes->contains(type) ? type : QQmlJSScope::ConstPtr();
|
||||
}
|
||||
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::originalContainedType(
|
||||
|
@ -502,8 +442,8 @@ void QQmlJSTypeResolver::adjustTrackedType(
|
|||
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
|
||||
return;
|
||||
|
||||
const auto it = m_typeTracker->trackedTypes.find(tracked);
|
||||
Q_ASSERT(it != m_typeTracker->trackedTypes.end());
|
||||
const auto it = m_trackedTypes->find(tracked);
|
||||
Q_ASSERT(it != m_trackedTypes->end());
|
||||
it->replacement = comparableType(conversion);
|
||||
*it->clone = std::move(*QQmlJSScope::clone(conversion));
|
||||
}
|
||||
|
@ -514,8 +454,8 @@ void QQmlJSTypeResolver::adjustTrackedType(
|
|||
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
|
||||
return;
|
||||
|
||||
const auto it = m_typeTracker->trackedTypes.find(tracked);
|
||||
Q_ASSERT(it != m_typeTracker->trackedTypes.end());
|
||||
const auto it = m_trackedTypes->find(tracked);
|
||||
Q_ASSERT(it != m_trackedTypes->end());
|
||||
QQmlJSScope::Ptr mutableTracked = it->clone;
|
||||
QQmlJSScope::ConstPtr result;
|
||||
for (const QQmlJSScope::ConstPtr &type : conversions)
|
||||
|
@ -534,8 +474,8 @@ void QQmlJSTypeResolver::generalizeType(const QQmlJSScope::ConstPtr &type) const
|
|||
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
|
||||
return;
|
||||
|
||||
const auto it = m_typeTracker->trackedTypes.find(type);
|
||||
Q_ASSERT(it != m_typeTracker->trackedTypes.end());
|
||||
const auto it = m_trackedTypes->find(type);
|
||||
Q_ASSERT(it != m_trackedTypes->end());
|
||||
*it->clone = std::move(*QQmlJSScope::clone(genericType(type)));
|
||||
if (it->replacement)
|
||||
it->replacement = genericType(it->replacement);
|
||||
|
@ -714,8 +654,9 @@ bool QQmlJSTypeResolver::canHoldUndefined(const QQmlJSRegisterContent &content)
|
|||
return false;
|
||||
}
|
||||
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPtr &type,
|
||||
ComponentIsGeneric allowComponent) const
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(
|
||||
const QQmlJSScope::ConstPtr &type,
|
||||
ComponentIsGeneric allowComponent) const
|
||||
{
|
||||
if (type->isScript())
|
||||
return m_jsValueType;
|
||||
|
@ -757,7 +698,10 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
|
|||
return m_jsValueType;
|
||||
}
|
||||
|
||||
if (isPrimitive(type) || equals(type, m_jsValueType) || equals(type, m_listPropertyType)
|
||||
if (type->isListProperty())
|
||||
return m_listPropertyType;
|
||||
|
||||
if (isPrimitive(type) || equals(type, m_jsValueType)
|
||||
|| equals(type, m_urlType) || equals(type, m_dateTimeType)
|
||||
|| equals(type, m_variantListType) || equals(type, m_varType)
|
||||
|| equals(type, m_stringListType) || equals(type, m_emptyListType)
|
||||
|
@ -772,10 +716,16 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
|
|||
return m_realType;
|
||||
|
||||
if (type->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence) {
|
||||
if (equals(type, m_listPropertyType))
|
||||
return type;
|
||||
if (const QQmlJSScope::ConstPtr valueType = type->valueType())
|
||||
return listType(genericType(valueType), UseQObjectList);
|
||||
if (const QQmlJSScope::ConstPtr valueType = type->valueType()) {
|
||||
switch (valueType->accessSemantics()) {
|
||||
case QQmlJSScope::AccessSemantics::Value:
|
||||
return genericType(valueType)->listType();
|
||||
case QQmlJSScope::AccessSemantics::Reference:
|
||||
return m_qObjectListType;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_varType;
|
||||
|
@ -868,9 +818,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr
|
|||
}
|
||||
}
|
||||
result = QQmlJSRegisterContent::create(
|
||||
prop.isList()
|
||||
? listType(prop.type(), UseListReference)
|
||||
: storedType(prop.type()),
|
||||
storedType(prop.type()),
|
||||
prop, scopeContentVariant(mode, false), scope);
|
||||
return true;
|
||||
}
|
||||
|
@ -1062,9 +1010,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr
|
|||
if (scope->hasOwnProperty(name)) {
|
||||
const auto prop = scope->ownProperty(name);
|
||||
result = QQmlJSRegisterContent::create(
|
||||
prop.isList()
|
||||
? listType(prop.type(), UseListReference)
|
||||
: storedType(prop.type()),
|
||||
storedType(prop.type()),
|
||||
prop,
|
||||
mode == QQmlJSScope::NotExtension
|
||||
? QQmlJSRegisterContent::ObjectProperty
|
||||
|
@ -1156,16 +1102,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSRegisterContent
|
|||
// we might have an enum of the attaching type.
|
||||
return memberEnumType(type.scopeType(), name);
|
||||
}
|
||||
if (type.isProperty()) {
|
||||
const auto prop = type.property();
|
||||
if (prop.isList()) {
|
||||
const QQmlJSScope::ConstPtr propType = listType(prop.type(), UseListReference);
|
||||
if (name == u"length"_s)
|
||||
return lengthProperty(true, propType);
|
||||
return memberType(propType, name);
|
||||
}
|
||||
return memberType(prop.type(), name);
|
||||
}
|
||||
if (type.isProperty())
|
||||
return memberType(type.property().type(), name);
|
||||
if (type.isEnumeration()) {
|
||||
const auto enumeration = type.enumeration();
|
||||
if (!type.enumMember().isEmpty() || !enumeration.hasKey(name))
|
||||
|
@ -1225,13 +1163,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::valueType(const QQmlJSRegisterContent
|
|||
value = valueType(list.conversionResult());
|
||||
} else if (list.isProperty()) {
|
||||
const auto prop = list.property();
|
||||
if (prop.isList()) {
|
||||
scope = listType(prop.type(), UseListReference);
|
||||
value = prop.type();
|
||||
} else {
|
||||
scope = prop.type();
|
||||
value = valueType(scope);
|
||||
}
|
||||
scope = prop.type();
|
||||
value = valueType(scope);
|
||||
}
|
||||
|
||||
if (value.isNull())
|
||||
|
@ -1268,12 +1201,8 @@ bool QQmlJSTypeResolver::registerContains(const QQmlJSRegisterContent ®,
|
|||
return equals(reg.type(), type);
|
||||
if (reg.isConversion())
|
||||
return equals(reg.conversionResult(), type);
|
||||
if (reg.isProperty()) {
|
||||
const auto prop = reg.property();
|
||||
return prop.isList()
|
||||
? equals(type, listType(prop.type(), UseListReference))
|
||||
: equals(type, prop.type());
|
||||
}
|
||||
if (reg.isProperty())
|
||||
return equals(type, reg.property().type());
|
||||
if (reg.isEnumeration())
|
||||
return equals(type, reg.enumeration().type());
|
||||
if (reg.isMethod())
|
||||
|
@ -1303,8 +1232,8 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::storedType(const QQmlJSScope::ConstPtr
|
|||
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::originalType(const QQmlJSScope::ConstPtr &type) const
|
||||
{
|
||||
const auto it = m_typeTracker->trackedTypes.find(type);
|
||||
return it == m_typeTracker->trackedTypes.end() ? type : it->original;
|
||||
const auto it = m_trackedTypes->find(type);
|
||||
return it == m_trackedTypes->end() ? type : it->original;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1336,8 +1265,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::convert(
|
|||
|
||||
QQmlJSScope::ConstPtr QQmlJSTypeResolver::comparableType(const QQmlJSScope::ConstPtr &type) const
|
||||
{
|
||||
const auto it = m_typeTracker->trackedTypes.constFind(type);
|
||||
if (it == m_typeTracker->trackedTypes.constEnd())
|
||||
const auto it = m_trackedTypes->constFind(type);
|
||||
if (it == m_trackedTypes->constEnd())
|
||||
return type;
|
||||
return it->replacement ? it->replacement : it->original;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSTypeResolver
|
|||
public:
|
||||
enum ParentMode { UseDocumentParent, UseParentProperty };
|
||||
enum CloneMode { CloneTypes, DoNotCloneTypes };
|
||||
enum ListMode { UseListProperty, UseQObjectList };
|
||||
|
||||
QQmlJSTypeResolver(QQmlJSImporter *importer);
|
||||
|
||||
|
@ -59,6 +60,7 @@ public:
|
|||
QQmlJSScope::ConstPtr metaObjectType() const { return m_metaObjectType; }
|
||||
QQmlJSScope::ConstPtr functionType() const { return m_functionType; }
|
||||
QQmlJSScope::ConstPtr jsGlobalObject() const { return m_jsGlobalObject; }
|
||||
QQmlJSScope::ConstPtr qObjectListType() const { return m_qObjectListType; }
|
||||
|
||||
QQmlJSScope::ConstPtr scopeForLocation(const QV4::CompiledData::Location &location) const;
|
||||
QQmlJSScope::ConstPtr scopeForId(
|
||||
|
@ -69,8 +71,6 @@ public:
|
|||
return m_imports.hasType(name) && !m_imports.type(name).scope;
|
||||
}
|
||||
|
||||
enum ListMode { UseListReference, UseQObjectList };
|
||||
QQmlJSScope::ConstPtr listType(const QQmlJSScope::ConstPtr &elementType, ListMode mode) const;
|
||||
QQmlJSScope::ConstPtr typeForName(const QString &name) const
|
||||
{
|
||||
return m_imports.type(name).scope;
|
||||
|
@ -169,7 +169,6 @@ protected:
|
|||
bool canPrimitivelyConvertFromTo(
|
||||
const QQmlJSScope::ConstPtr &from, const QQmlJSScope::ConstPtr &to) const;
|
||||
QQmlJSRegisterContent lengthProperty(bool isWritable, const QQmlJSScope::ConstPtr &scope) const;
|
||||
void trackListPropertyType(const QQmlJSScope::ConstPtr &trackedListElementType) const;
|
||||
QQmlJSRegisterContent transformed(
|
||||
const QQmlJSRegisterContent &origin,
|
||||
QQmlJSScope::ConstPtr (QQmlJSTypeResolver::*op)(const QQmlJSScope::ConstPtr &) const) const;
|
||||
|
@ -199,6 +198,7 @@ protected:
|
|||
QQmlJSScope::ConstPtr m_jsValueType;
|
||||
QQmlJSScope::ConstPtr m_jsPrimitiveType;
|
||||
QQmlJSScope::ConstPtr m_listPropertyType;
|
||||
QQmlJSScope::ConstPtr m_qObjectListType;
|
||||
QQmlJSScope::ConstPtr m_metaObjectType;
|
||||
QQmlJSScope::ConstPtr m_functionType;
|
||||
QQmlJSScope::ConstPtr m_jsGlobalObject;
|
||||
|
@ -225,13 +225,7 @@ protected:
|
|||
QQmlJSScope::Ptr clone;
|
||||
};
|
||||
|
||||
struct TypeTracker
|
||||
{
|
||||
QHash<QQmlJSScope::ConstPtr, QQmlJSScope::Ptr> listTypes;
|
||||
QHash<QQmlJSScope::ConstPtr, TrackedType> trackedTypes;
|
||||
};
|
||||
|
||||
std::unique_ptr<TypeTracker> m_typeTracker;
|
||||
std::unique_ptr<QHash<QQmlJSScope::ConstPtr, TrackedType>> m_trackedTypes;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -107,6 +107,7 @@ set(qml_files
|
|||
jsmoduleimport.qml
|
||||
layouts.qml
|
||||
library.js
|
||||
listAsArgument.qml
|
||||
listIndices.qml
|
||||
listPropertyAsModel.qml
|
||||
listlength.qml
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
pragma Strict
|
||||
import QtQml
|
||||
|
||||
QtObject {
|
||||
function selectSecondInt(a: list<int>): int {
|
||||
return a[1]
|
||||
}
|
||||
|
||||
function returnInts1(): list<int> {
|
||||
return l
|
||||
}
|
||||
|
||||
function returnInts2(): list<int> {
|
||||
return [1, 2, 3, 4]
|
||||
}
|
||||
|
||||
function selectSecondDummy(a: list<Dummy>): Dummy {
|
||||
return a[1]
|
||||
}
|
||||
|
||||
property list<int> l: [5, 4, 3, 2, 1]
|
||||
property int i: selectSecondInt(l)
|
||||
property int j: selectSecondInt([1, 2, 3, 4, 5])
|
||||
property int i1: returnInts1()[3]
|
||||
property int i2: returnInts2()[3]
|
||||
|
||||
property list<Dummy> dummies: [
|
||||
Dummy{ objectName: "a"},
|
||||
Dummy{ objectName: "this one" },
|
||||
Dummy{ }
|
||||
]
|
||||
property Dummy d: selectSecondDummy(dummies)
|
||||
}
|
|
@ -141,6 +141,7 @@ private slots:
|
|||
void inaccessibleProperty();
|
||||
void typePropagationLoop();
|
||||
void signatureIgnored();
|
||||
void listAsArgument();
|
||||
};
|
||||
|
||||
void tst_QmlCppCodegen::initTestCase()
|
||||
|
@ -2750,6 +2751,21 @@ void tst_QmlCppCodegen::signatureIgnored()
|
|||
QCOMPARE(ignored->property("n").toInt(), 67);
|
||||
}
|
||||
|
||||
void tst_QmlCppCodegen::listAsArgument()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
|
||||
QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/listAsArgument.qml"_s));
|
||||
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||
|
||||
QScopedPointer<QObject> o(c.create());
|
||||
QCOMPARE(o->property("i").toInt(), 4);
|
||||
QCOMPARE(o->property("j").toInt(), 2);
|
||||
QCOMPARE(o->property("i1").toInt(), 2);
|
||||
QCOMPARE(o->property("i2").toInt(), 4);
|
||||
QCOMPARE(o->property("d").value<QObject *>()->objectName(), u"this one"_s);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QmlCppCodegen)
|
||||
|
||||
#include "tst_qmlcppcodegen.moc"
|
||||
|
|
|
@ -17,7 +17,9 @@ using namespace Qt::StringLiterals;
|
|||
|
||||
bool qIsReferenceTypeList(const QQmlJSMetaProperty &p)
|
||||
{
|
||||
return p.isList() && p.type()->isReferenceType();
|
||||
if (QQmlJSScope::ConstPtr type = p.type())
|
||||
return type->isListProperty();
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQmltcCompiler, "qml.qmltc.compiler", QtWarningMsg);
|
||||
|
@ -474,6 +476,7 @@ void QmltcCompiler::compileMethod(QmltcType ¤t, const QQmlJSMetaMethod &m,
|
|||
void QmltcCompiler::compileExtraListMethods(QmltcType ¤t, const QQmlJSMetaProperty &p)
|
||||
{
|
||||
QmltcPropertyData data(p);
|
||||
const QString valueType = p.type()->valueType()->internalName() + u'*';
|
||||
const QString variableName = data.read + u"()"_s;
|
||||
const QStringList ownershipWarning = {
|
||||
u"\\note {This method does not change the ownership of its argument."_s,
|
||||
|
@ -490,7 +493,7 @@ void QmltcCompiler::compileExtraListMethods(QmltcType ¤t, const QQmlJSMeta
|
|||
append.comments << ownershipWarning;
|
||||
append.returnType = u"void"_s;
|
||||
append.name = u"%1Append"_s.arg(data.read);
|
||||
append.parameterList.emplaceBack(u"%1*"_s.arg(p.type()->internalName()), u"toBeAppended"_s);
|
||||
append.parameterList.emplaceBack(valueType, u"toBeAppended"_s);
|
||||
|
||||
append.body << u"auto q_qmltc_localList = %1;"_s.arg(variableName);
|
||||
append.body
|
||||
|
@ -519,7 +522,7 @@ void QmltcCompiler::compileExtraListMethods(QmltcType ¤t, const QQmlJSMeta
|
|||
{
|
||||
QmltcMethod at{};
|
||||
at.comments.emplaceBack(u"\\brief Access an element in %1."_s.arg(data.read));
|
||||
at.returnType = u"%1*"_s.arg(p.type()->internalName());
|
||||
at.returnType = valueType;
|
||||
at.name = u"%1At"_s.arg(data.read);
|
||||
at.parameterList.emplaceBack(u"qsizetype"_s, u"position"_s, QString());
|
||||
|
||||
|
@ -553,7 +556,7 @@ void QmltcCompiler::compileExtraListMethods(QmltcType ¤t, const QQmlJSMeta
|
|||
replace.returnType = u"void"_s;
|
||||
replace.name = u"%1Replace"_s.arg(data.read);
|
||||
replace.parameterList.emplaceBack(u"qsizetype"_s, u"position"_s, QString());
|
||||
replace.parameterList.emplaceBack(u"%1*"_s.arg(p.type()->internalName()), u"element"_s,
|
||||
replace.parameterList.emplaceBack(valueType, u"element"_s,
|
||||
QString());
|
||||
|
||||
replace.body << u"auto q_qmltc_localList = %1;"_s.arg(variableName);
|
||||
|
@ -593,8 +596,9 @@ void QmltcCompiler::compileProperty(QmltcType ¤t, const QQmlJSMetaProperty
|
|||
const QString underlyingType = getUnderlyingType(p);
|
||||
if (qIsReferenceTypeList(p)) {
|
||||
const QString storageName = variableName + u"_storage";
|
||||
current.variables.emplaceBack(u"QList<" + p.type()->internalName() + u"*>", storageName,
|
||||
QString());
|
||||
current.variables.emplaceBack(
|
||||
u"QList<" + p.type()->valueType()->internalName() + u"*>", storageName,
|
||||
QString());
|
||||
current.baselineCtor.initializerList.emplaceBack(variableName + u"(" + underlyingType
|
||||
+ u"(this, std::addressof(" + storageName
|
||||
+ u")))");
|
||||
|
|
|
@ -97,7 +97,8 @@ void QmltcCodeGenerator::generate_assignToListProperty(
|
|||
type, p, QmltcCodeGenerator::wrap_privateClass(accessor, p));
|
||||
|
||||
qmlListVarName = u"listprop_%1"_s.arg(p.propertyName());
|
||||
*block << u"QQmlListProperty<%1> %2;"_s.arg(p.type()->internalName(), qmlListVarName);
|
||||
QQmlJSScope::ConstPtr valueType = p.type()->valueType();
|
||||
*block << u"QQmlListProperty<%1> %2;"_s.arg(valueType->internalName(), qmlListVarName);
|
||||
*block << extensionPrologue;
|
||||
*block << u"%1 = %2->%3();"_s.arg(qmlListVarName, extensionAccessor, p.read());
|
||||
*block << extensionEpilogue;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#define QMLTCPROPERTYUTILS_H
|
||||
|
||||
#include <private/qqmljsmetatypes_p.h>
|
||||
#include <private/qqmljsscope_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -15,19 +16,15 @@ QT_BEGIN_NAMESPACE
|
|||
*/
|
||||
inline QString getUnderlyingType(const QQmlJSMetaProperty &p)
|
||||
{
|
||||
QString underlyingType = p.type()->internalName();
|
||||
// NB: can be a pointer or a list, can't be both (list automatically assumes
|
||||
// that it holds pointers though). check isList() first, as list<QtObject>
|
||||
// would be both a list and a pointer (weird).
|
||||
if (p.isList()) {
|
||||
if (p.type()->isReferenceType())
|
||||
underlyingType = u"QQmlListProperty<" + underlyingType + u">";
|
||||
else
|
||||
underlyingType = u"QList<" + underlyingType + u">";
|
||||
} else if (p.type()->isReferenceType()) {
|
||||
underlyingType += u'*';
|
||||
// We cannot just use p.type()->internalName() here because it may be
|
||||
// a list property of something that only receives a C++ name from qmltc.
|
||||
const QQmlJSScope::ConstPtr valueType = p.type()->valueType();
|
||||
return (valueType->isReferenceType() ? u"QQmlListProperty<" : u"QList<")
|
||||
+ valueType->internalName() + u'>';
|
||||
}
|
||||
return underlyingType;
|
||||
|
||||
return p.type()->augmentedInternalName();
|
||||
}
|
||||
|
||||
// simple class that, for a given property, creates information for the
|
||||
|
|
Loading…
Reference in New Issue