Compiler: Handle method list return types from qmltypes file
When parsing methods details from qmltypes files, the `isList` value was ignored. It indicates that the return type of the method is a list of the type specified in the `type` value. Add the isList flag to QQmlJSMetaParameter and make the return value a QQmlJSMetaParameter, too, so that we can pass the flag to the type resolution. Fixes: QTBUG-122106 Change-Id: I6ea07c02fbeb6cb07d9fe9184205ff7f3274fd73 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commite303d12827
) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit411f6cce09
) (cherry picked from commit7d3204ff06
) Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
This commit is contained in:
parent
76d22624ed
commit
dd865c1a62
|
@ -120,7 +120,7 @@ public:
|
||||||
Const,
|
Const,
|
||||||
};
|
};
|
||||||
|
|
||||||
QQmlJSMetaParameter(const QString &name, const QString &typeName,
|
QQmlJSMetaParameter(const QString &name = QString(), const QString &typeName = QString(),
|
||||||
Constness typeQualifier = NonConst,
|
Constness typeQualifier = NonConst,
|
||||||
QWeakPointer<const QQmlJSScope> type = {})
|
QWeakPointer<const QQmlJSScope> type = {})
|
||||||
: m_name(name), m_typeName(typeName), m_type(type), m_typeQualifier(typeQualifier)
|
: m_name(name), m_typeName(typeName), m_type(type), m_typeQualifier(typeQualifier)
|
||||||
|
@ -135,9 +135,13 @@ public:
|
||||||
void setType(QWeakPointer<const QQmlJSScope> type) { m_type = type; }
|
void setType(QWeakPointer<const QQmlJSScope> type) { m_type = type; }
|
||||||
Constness typeQualifier() const { return m_typeQualifier; }
|
Constness typeQualifier() const { return m_typeQualifier; }
|
||||||
void setTypeQualifier(Constness typeQualifier) { m_typeQualifier = typeQualifier; }
|
void setTypeQualifier(Constness typeQualifier) { m_typeQualifier = typeQualifier; }
|
||||||
|
|
||||||
bool isPointer() const { return m_isPointer; }
|
bool isPointer() const { return m_isPointer; }
|
||||||
void setIsPointer(bool isPointer) { m_isPointer = isPointer; }
|
void setIsPointer(bool isPointer) { m_isPointer = isPointer; }
|
||||||
|
|
||||||
|
bool isList() const { return m_isList; }
|
||||||
|
void setIsList(bool isList) { m_isList = isList; }
|
||||||
|
|
||||||
friend bool operator==(const QQmlJSMetaParameter &a, const QQmlJSMetaParameter &b)
|
friend bool operator==(const QQmlJSMetaParameter &a, const QQmlJSMetaParameter &b)
|
||||||
{
|
{
|
||||||
return a.m_name == b.m_name && a.m_typeName == b.m_typeName
|
return a.m_name == b.m_name && a.m_typeName == b.m_typeName
|
||||||
|
@ -162,8 +166,11 @@ private:
|
||||||
QWeakPointer<const QQmlJSScope> m_type;
|
QWeakPointer<const QQmlJSScope> m_type;
|
||||||
Constness m_typeQualifier = NonConst;
|
Constness m_typeQualifier = NonConst;
|
||||||
bool m_isPointer = false;
|
bool m_isPointer = false;
|
||||||
|
bool m_isList = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using QQmlJSMetaReturnType = QQmlJSMetaParameter;
|
||||||
|
|
||||||
class QQmlJSMetaMethod
|
class QQmlJSMetaMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -191,20 +198,18 @@ public:
|
||||||
QQmlJSMetaMethod() = default;
|
QQmlJSMetaMethod() = default;
|
||||||
explicit QQmlJSMetaMethod(QString name, QString returnType = QString())
|
explicit QQmlJSMetaMethod(QString name, QString returnType = QString())
|
||||||
: m_name(std::move(name))
|
: m_name(std::move(name))
|
||||||
, m_returnTypeName(std::move(returnType))
|
, m_returnType(QString(), std::move(returnType))
|
||||||
, m_methodType(Method)
|
, m_methodType(Method)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QString methodName() const { return m_name; }
|
QString methodName() const { return m_name; }
|
||||||
void setMethodName(const QString &name) { m_name = name; }
|
void setMethodName(const QString &name) { m_name = name; }
|
||||||
|
|
||||||
QString returnTypeName() const { return m_returnTypeName; }
|
QQmlJSMetaReturnType returnValue() const { return m_returnType; }
|
||||||
QSharedPointer<const QQmlJSScope> returnType() const { return m_returnType.toStrongRef(); }
|
void setReturnValue(const QQmlJSMetaReturnType returnValue) { m_returnType = returnValue; }
|
||||||
void setReturnTypeName(const QString &type) { m_returnTypeName = type; }
|
QString returnTypeName() const { return m_returnType.typeName(); }
|
||||||
void setReturnType(const QSharedPointer<const QQmlJSScope> &type)
|
QSharedPointer<const QQmlJSScope> returnType() const { return m_returnType.type(); }
|
||||||
{
|
void setReturnTypeName(const QString &type) { m_returnType.setTypeName(type); }
|
||||||
m_returnType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QQmlJSMetaParameter> parameters() const { return m_parameters; }
|
QList<QQmlJSMetaParameter> parameters() const { return m_parameters; }
|
||||||
|
|
||||||
|
@ -257,7 +262,7 @@ public:
|
||||||
|
|
||||||
friend bool operator==(const QQmlJSMetaMethod &a, const QQmlJSMetaMethod &b)
|
friend bool operator==(const QQmlJSMetaMethod &a, const QQmlJSMetaMethod &b)
|
||||||
{
|
{
|
||||||
return a.m_name == b.m_name && a.m_returnTypeName == b.m_returnTypeName
|
return a.m_name == b.m_name && a.m_returnType == b.m_returnType
|
||||||
&& a.m_returnType == b.m_returnType && a.m_parameters == b.m_parameters
|
&& a.m_returnType == b.m_returnType && a.m_parameters == b.m_parameters
|
||||||
&& a.m_annotations == b.m_annotations && a.m_methodType == b.m_methodType
|
&& a.m_annotations == b.m_annotations && a.m_methodType == b.m_methodType
|
||||||
&& a.m_methodAccess == b.m_methodAccess && a.m_revision == b.m_revision
|
&& a.m_methodAccess == b.m_methodAccess && a.m_revision == b.m_revision
|
||||||
|
@ -274,8 +279,7 @@ public:
|
||||||
QtPrivate::QHashCombine combine;
|
QtPrivate::QHashCombine combine;
|
||||||
|
|
||||||
seed = combine(seed, method.m_name);
|
seed = combine(seed, method.m_name);
|
||||||
seed = combine(seed, method.m_returnTypeName);
|
seed = combine(seed, method.m_returnType);
|
||||||
seed = combine(seed, method.m_returnType.toStrongRef().data());
|
|
||||||
seed = combine(seed, method.m_annotations);
|
seed = combine(seed, method.m_annotations);
|
||||||
seed = combine(seed, method.m_methodType);
|
seed = combine(seed, method.m_methodType);
|
||||||
seed = combine(seed, method.m_methodAccess);
|
seed = combine(seed, method.m_methodAccess);
|
||||||
|
@ -291,8 +295,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_name;
|
QString m_name;
|
||||||
QString m_returnTypeName;
|
|
||||||
QWeakPointer<const QQmlJSScope> m_returnType;
|
QQmlJSMetaReturnType m_returnType;
|
||||||
|
|
||||||
QList<QQmlJSMetaParameter> m_parameters;
|
QList<QQmlJSMetaParameter> m_parameters;
|
||||||
QList<QQmlJSAnnotation> m_annotations;
|
QList<QQmlJSAnnotation> m_annotations;
|
||||||
|
|
|
@ -502,24 +502,26 @@ QTypeRevision QQmlJSScope::resolveType(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
|
const auto resolveParameter = [&](QQmlJSMetaParameter ¶meter) {
|
||||||
const QString returnTypeName = it->returnTypeName();
|
if (const QString typeName = parameter.typeName();
|
||||||
if (!it->returnType() && !returnTypeName.isEmpty()) {
|
!parameter.type() && !typeName.isEmpty()) {
|
||||||
const auto returnType = findType(returnTypeName, context, usedTypes);
|
const auto type = findType(typeName, context, usedTypes);
|
||||||
it->setReturnType(returnType.scope);
|
if (type.scope && type.scope->isReferenceType())
|
||||||
|
parameter.setIsPointer(true);
|
||||||
|
parameter.setType({ (type.scope && parameter.isList())
|
||||||
|
? type.scope->listType()
|
||||||
|
: type.scope });
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
|
||||||
|
auto returnValue = it->returnValue();
|
||||||
|
resolveParameter(returnValue);
|
||||||
|
it->setReturnValue(returnValue);
|
||||||
|
|
||||||
auto parameters = it->parameters();
|
auto parameters = it->parameters();
|
||||||
for (int i = 0, length = parameters.size(); i < length; ++i) {
|
for (int i = 0, length = parameters.size(); i < length; ++i)
|
||||||
auto ¶meter = parameters[i];
|
resolveParameter(parameters[i]);
|
||||||
if (const QString typeName = parameter.typeName();
|
|
||||||
!parameter.type() && !typeName.isEmpty()) {
|
|
||||||
const auto type = findType(typeName, context, usedTypes);
|
|
||||||
if (type.scope && type.scope->isReferenceType())
|
|
||||||
parameter.setIsPointer(true);
|
|
||||||
parameter.setType({ type.scope });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
it->setParameters(parameters);
|
it->setParameters(parameters);
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,7 +299,9 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bo
|
||||||
} else if (name == QLatin1String("isJavaScriptFunction")) {
|
} else if (name == QLatin1String("isJavaScriptFunction")) {
|
||||||
metaMethod.setIsJavaScriptFunction(true);
|
metaMethod.setIsJavaScriptFunction(true);
|
||||||
} else if (name == QLatin1String("isList")) {
|
} else if (name == QLatin1String("isList")) {
|
||||||
// TODO: Theoretically this can happen. QQmlJSMetaMethod should store it.
|
auto metaReturnType = metaMethod.returnValue();
|
||||||
|
metaReturnType.setIsList(true);
|
||||||
|
metaMethod.setReturnValue(metaReturnType);
|
||||||
} else if (name == QLatin1String("isPointer")) {
|
} else if (name == QLatin1String("isPointer")) {
|
||||||
// TODO: We don't need this information. We can probably drop all isPointer members
|
// TODO: We don't need this information. We can probably drop all isPointer members
|
||||||
// once we make sure that the type information is always complete. The
|
// once we make sure that the type information is always complete. The
|
||||||
|
@ -429,6 +431,7 @@ void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSM
|
||||||
QString type;
|
QString type;
|
||||||
bool isConstant = false;
|
bool isConstant = false;
|
||||||
bool isPointer = false;
|
bool isPointer = false;
|
||||||
|
bool isList = false;
|
||||||
|
|
||||||
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
|
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
|
||||||
UiObjectMember *member = it->member;
|
UiObjectMember *member = it->member;
|
||||||
|
@ -450,7 +453,7 @@ void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSM
|
||||||
} else if (id == QLatin1String("isReadonly")) {
|
} else if (id == QLatin1String("isReadonly")) {
|
||||||
// ### unhandled
|
// ### unhandled
|
||||||
} else if (id == QLatin1String("isList")) {
|
} else if (id == QLatin1String("isList")) {
|
||||||
// ### unhandled
|
isList = readBoolBinding(script);
|
||||||
} else {
|
} else {
|
||||||
addWarning(script->firstSourceLocation(),
|
addWarning(script->firstSourceLocation(),
|
||||||
tr("Expected only name and type script bindings."));
|
tr("Expected only name and type script bindings."));
|
||||||
|
@ -460,6 +463,7 @@ void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSM
|
||||||
QQmlJSMetaParameter p(name, type);
|
QQmlJSMetaParameter p(name, type);
|
||||||
p.setTypeQualifier(isConstant ? QQmlJSMetaParameter::Const : QQmlJSMetaParameter::NonConst);
|
p.setTypeQualifier(isConstant ? QQmlJSMetaParameter::Const : QQmlJSMetaParameter::NonConst);
|
||||||
p.setIsPointer(isPointer);
|
p.setIsPointer(isPointer);
|
||||||
|
p.setIsList(isList);
|
||||||
metaMethod->addParameter(std::move(p));
|
metaMethod->addParameter(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ set(cpp_sources
|
||||||
enumProperty.h
|
enumProperty.h
|
||||||
gadgetwithenum.h
|
gadgetwithenum.h
|
||||||
invisible.h
|
invisible.h
|
||||||
|
listprovider.h
|
||||||
multiforeign.h
|
multiforeign.h
|
||||||
objectwithmethod.h
|
objectwithmethod.h
|
||||||
person.cpp person.h
|
person.cpp person.h
|
||||||
|
@ -37,6 +38,7 @@ set(qml_files
|
||||||
Cycle1.qml
|
Cycle1.qml
|
||||||
Cycle2.qml
|
Cycle2.qml
|
||||||
Cycle3.qml
|
Cycle3.qml
|
||||||
|
CppMethodListReturnType.qml
|
||||||
CxxTypeFromDir.qml
|
CxxTypeFromDir.qml
|
||||||
CxxTypeFromImplicit.qml
|
CxxTypeFromImplicit.qml
|
||||||
Dummy.qml
|
Dummy.qml
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
pragma Strict
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import TestTypes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
ListProvider {
|
||||||
|
id: listProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
property var list: listProvider.intList()
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef QLISTPROVIDER_H
|
||||||
|
#define QLISTPROVIDER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
class QListProvider : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_NAMED_ELEMENT(ListProvider)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QListProvider(QObject *parent = nullptr) : QObject(parent) { }
|
||||||
|
|
||||||
|
Q_INVOKABLE QList<int> intList() const
|
||||||
|
{
|
||||||
|
QList<int> list;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
list.append(i);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QLISTPROVIDER_H
|
|
@ -29,6 +29,7 @@ private slots:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
|
|
||||||
void simpleBinding();
|
void simpleBinding();
|
||||||
|
void cppMethodListReturnType();
|
||||||
void cppValueTypeList();
|
void cppValueTypeList();
|
||||||
void anchorsFill();
|
void anchorsFill();
|
||||||
void signalHandler();
|
void signalHandler();
|
||||||
|
@ -221,6 +222,17 @@ void tst_QmlCppCodegen::simpleBinding()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QmlCppCodegen::cppMethodListReturnType()
|
||||||
|
{
|
||||||
|
QQmlEngine engine;
|
||||||
|
QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/CppMethodListReturnType.qml"_s));
|
||||||
|
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||||
|
QScopedPointer<QObject> o(c.create());
|
||||||
|
QVERIFY(!o.isNull());
|
||||||
|
|
||||||
|
QCOMPARE(o->property("list").toList()[2].toInt(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QmlCppCodegen::cppValueTypeList()
|
void tst_QmlCppCodegen::cppValueTypeList()
|
||||||
{
|
{
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
|
|
Loading…
Reference in New Issue