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,
|
||||
};
|
||||
|
||||
QQmlJSMetaParameter(const QString &name, const QString &typeName,
|
||||
QQmlJSMetaParameter(const QString &name = QString(), const QString &typeName = QString(),
|
||||
Constness typeQualifier = NonConst,
|
||||
QWeakPointer<const QQmlJSScope> type = {})
|
||||
: 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; }
|
||||
Constness typeQualifier() const { return m_typeQualifier; }
|
||||
void setTypeQualifier(Constness typeQualifier) { m_typeQualifier = typeQualifier; }
|
||||
|
||||
bool isPointer() const { return m_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)
|
||||
{
|
||||
return a.m_name == b.m_name && a.m_typeName == b.m_typeName
|
||||
|
@ -162,8 +166,11 @@ private:
|
|||
QWeakPointer<const QQmlJSScope> m_type;
|
||||
Constness m_typeQualifier = NonConst;
|
||||
bool m_isPointer = false;
|
||||
bool m_isList = false;
|
||||
};
|
||||
|
||||
using QQmlJSMetaReturnType = QQmlJSMetaParameter;
|
||||
|
||||
class QQmlJSMetaMethod
|
||||
{
|
||||
public:
|
||||
|
@ -191,20 +198,18 @@ public:
|
|||
QQmlJSMetaMethod() = default;
|
||||
explicit QQmlJSMetaMethod(QString name, QString returnType = QString())
|
||||
: m_name(std::move(name))
|
||||
, m_returnTypeName(std::move(returnType))
|
||||
, m_returnType(QString(), std::move(returnType))
|
||||
, m_methodType(Method)
|
||||
{}
|
||||
|
||||
QString methodName() const { return m_name; }
|
||||
void setMethodName(const QString &name) { m_name = name; }
|
||||
|
||||
QString returnTypeName() const { return m_returnTypeName; }
|
||||
QSharedPointer<const QQmlJSScope> returnType() const { return m_returnType.toStrongRef(); }
|
||||
void setReturnTypeName(const QString &type) { m_returnTypeName = type; }
|
||||
void setReturnType(const QSharedPointer<const QQmlJSScope> &type)
|
||||
{
|
||||
m_returnType = type;
|
||||
}
|
||||
QQmlJSMetaReturnType returnValue() const { return m_returnType; }
|
||||
void setReturnValue(const QQmlJSMetaReturnType returnValue) { m_returnType = returnValue; }
|
||||
QString returnTypeName() const { return m_returnType.typeName(); }
|
||||
QSharedPointer<const QQmlJSScope> returnType() const { return m_returnType.type(); }
|
||||
void setReturnTypeName(const QString &type) { m_returnType.setTypeName(type); }
|
||||
|
||||
QList<QQmlJSMetaParameter> parameters() const { return m_parameters; }
|
||||
|
||||
|
@ -257,7 +262,7 @@ public:
|
|||
|
||||
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_annotations == b.m_annotations && a.m_methodType == b.m_methodType
|
||||
&& a.m_methodAccess == b.m_methodAccess && a.m_revision == b.m_revision
|
||||
|
@ -274,8 +279,7 @@ public:
|
|||
QtPrivate::QHashCombine combine;
|
||||
|
||||
seed = combine(seed, method.m_name);
|
||||
seed = combine(seed, method.m_returnTypeName);
|
||||
seed = combine(seed, method.m_returnType.toStrongRef().data());
|
||||
seed = combine(seed, method.m_returnType);
|
||||
seed = combine(seed, method.m_annotations);
|
||||
seed = combine(seed, method.m_methodType);
|
||||
seed = combine(seed, method.m_methodAccess);
|
||||
|
@ -291,8 +295,8 @@ public:
|
|||
|
||||
private:
|
||||
QString m_name;
|
||||
QString m_returnTypeName;
|
||||
QWeakPointer<const QQmlJSScope> m_returnType;
|
||||
|
||||
QQmlJSMetaReturnType m_returnType;
|
||||
|
||||
QList<QQmlJSMetaParameter> m_parameters;
|
||||
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 QString returnTypeName = it->returnTypeName();
|
||||
if (!it->returnType() && !returnTypeName.isEmpty()) {
|
||||
const auto returnType = findType(returnTypeName, context, usedTypes);
|
||||
it->setReturnType(returnType.scope);
|
||||
const auto resolveParameter = [&](QQmlJSMetaParameter ¶meter) {
|
||||
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 && 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();
|
||||
for (int i = 0, length = parameters.size(); i < length; ++i) {
|
||||
auto ¶meter = 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 });
|
||||
}
|
||||
}
|
||||
for (int i = 0, length = parameters.size(); i < length; ++i)
|
||||
resolveParameter(parameters[i]);
|
||||
|
||||
it->setParameters(parameters);
|
||||
}
|
||||
|
|
|
@ -299,7 +299,9 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bo
|
|||
} else if (name == QLatin1String("isJavaScriptFunction")) {
|
||||
metaMethod.setIsJavaScriptFunction(true);
|
||||
} 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")) {
|
||||
// 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
|
||||
|
@ -429,6 +431,7 @@ void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSM
|
|||
QString type;
|
||||
bool isConstant = false;
|
||||
bool isPointer = false;
|
||||
bool isList = false;
|
||||
|
||||
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
|
||||
UiObjectMember *member = it->member;
|
||||
|
@ -450,7 +453,7 @@ void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSM
|
|||
} else if (id == QLatin1String("isReadonly")) {
|
||||
// ### unhandled
|
||||
} else if (id == QLatin1String("isList")) {
|
||||
// ### unhandled
|
||||
isList = readBoolBinding(script);
|
||||
} else {
|
||||
addWarning(script->firstSourceLocation(),
|
||||
tr("Expected only name and type script bindings."));
|
||||
|
@ -460,6 +463,7 @@ void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSM
|
|||
QQmlJSMetaParameter p(name, type);
|
||||
p.setTypeQualifier(isConstant ? QQmlJSMetaParameter::Const : QQmlJSMetaParameter::NonConst);
|
||||
p.setIsPointer(isPointer);
|
||||
p.setIsList(isList);
|
||||
metaMethod->addParameter(std::move(p));
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ set(cpp_sources
|
|||
enumProperty.h
|
||||
gadgetwithenum.h
|
||||
invisible.h
|
||||
listprovider.h
|
||||
multiforeign.h
|
||||
objectwithmethod.h
|
||||
person.cpp person.h
|
||||
|
@ -37,6 +38,7 @@ set(qml_files
|
|||
Cycle1.qml
|
||||
Cycle2.qml
|
||||
Cycle3.qml
|
||||
CppMethodListReturnType.qml
|
||||
CxxTypeFromDir.qml
|
||||
CxxTypeFromImplicit.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 simpleBinding();
|
||||
void cppMethodListReturnType();
|
||||
void cppValueTypeList();
|
||||
void anchorsFill();
|
||||
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()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
|
|
Loading…
Reference in New Issue