Fix extension lookup in QQmlJSScope
Do not go over extension's base types since this is not how the engine logic work. Instead, only assess the direct extension type when traversing the base type hierarchy. The special cases are value types which still need base type extension traversal (e.g. due to Number and NumberPrototype extensions on primitives) and QObject type itself (we expect to see ObjectPrototype properties / methods of it) Pick-to: 6.3 6.2 Change-Id: I92ba979202b33f16e1a7b948d4f1e79df37f2669 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
11d2767f09
commit
a287e862d4
|
@ -177,6 +177,9 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSUtils
|
|||
template<typename QQmlJSScopePtr, typename Action>
|
||||
static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check)
|
||||
{
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
using namespace detail;
|
||||
|
||||
// NB: among other things, getQQmlJSScopeFromSmartPtr() also resolves const
|
||||
|
@ -196,17 +199,26 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSUtils
|
|||
}
|
||||
};
|
||||
|
||||
const bool isValueType = (type->accessSemantics() == QQmlJSScope::AccessSemantics::Value);
|
||||
|
||||
QDuplicateTracker<T> seen;
|
||||
for (T scope = type; scope && !seen.hasSeen(scope);
|
||||
scope = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->baseType())) {
|
||||
// Extensions override their base types
|
||||
QDuplicateTracker<T> seenExtensions;
|
||||
for (T extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->extensionType());
|
||||
extension && !seenExtensions.hasSeen(extension);
|
||||
extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(extension->baseType())) {
|
||||
// Extensions override the types they extend. However, usually base
|
||||
// types of extensions are ignored. The unusual cases are when we
|
||||
// have a value type or when we have the QObject type, in which case
|
||||
// we also study the extension's base type hierarchy.
|
||||
const bool isQObject = scope->internalName() == QLatin1String("QObject");
|
||||
T extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->extensionType());
|
||||
do {
|
||||
if (!extension || seenExtensions.hasSeen(extension))
|
||||
break;
|
||||
|
||||
if (checkWrapper(extension, QQmlJSScope::ExtensionType))
|
||||
return true;
|
||||
}
|
||||
extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(extension->baseType());
|
||||
} while (isValueType || isQObject);
|
||||
|
||||
if (checkWrapper(scope, QQmlJSScope::NotExtension))
|
||||
return true;
|
||||
|
|
|
@ -10,6 +10,7 @@ qt6_add_qml_module(qqmljsscope_test_module
|
|||
URI QQmlJSScopeTests
|
||||
SOURCES
|
||||
singleton.h singleton.cpp
|
||||
extensiontypes.h
|
||||
)
|
||||
|
||||
qt_autogen_tools_initial_setup(qqmljsscope_test_moduleplugin)
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef EXTENSIONTYPES_H
|
||||
#define EXTENSIONTYPES_H
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <qqml.h>
|
||||
|
||||
class Extension : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
Q_PROPERTY(int count READ getCount WRITE setCount NOTIFY countChanged)
|
||||
|
||||
public:
|
||||
Extension(QObject *parent = nullptr) : QObject(parent) { }
|
||||
int getCount() const { return 42; }
|
||||
void setCount(int) { }
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
};
|
||||
|
||||
class IndirectExtension : public Extension
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
public:
|
||||
IndirectExtension(QObject *parent = nullptr) : Extension(parent) { }
|
||||
};
|
||||
|
||||
class Extended : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_EXTENDED(Extension)
|
||||
Q_PROPERTY(double count READ getCount WRITE setCount NOTIFY countChanged)
|
||||
|
||||
public:
|
||||
Extended(QObject *parent = nullptr) : QObject(parent) { }
|
||||
double getCount() const { return 0.0; }
|
||||
void setCount(double) { }
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
};
|
||||
|
||||
class ExtendedIndirect : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_EXTENDED(IndirectExtension)
|
||||
Q_PROPERTY(double count READ getCount WRITE setCount NOTIFY countChanged)
|
||||
|
||||
public:
|
||||
ExtendedIndirect(QObject *parent = nullptr) : QObject(parent) { }
|
||||
double getCount() const { return 0; }
|
||||
void setCount(double) { }
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
};
|
||||
|
||||
class Extension2 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
Q_PROPERTY(QString str READ getStr WRITE setStr NOTIFY strChanged)
|
||||
|
||||
public:
|
||||
Extension2(QObject *parent = nullptr) : QObject(parent) { }
|
||||
QString getStr() const { return QStringLiteral("42"); }
|
||||
void setStr(QString) { }
|
||||
Q_SIGNALS:
|
||||
void strChanged();
|
||||
};
|
||||
|
||||
class ExtendedTwice : public Extended
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_EXTENDED(Extension2)
|
||||
Q_PROPERTY(QByteArray str READ getStr WRITE setStr)
|
||||
|
||||
public:
|
||||
ExtendedTwice(QObject *parent = nullptr) : Extended(parent) { }
|
||||
QByteArray getStr() const { return QByteArray(); }
|
||||
void setStr(QByteArray) { }
|
||||
};
|
||||
|
||||
#endif // EXTENSIONTYPES_H
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick
|
||||
import QQmlJSScopeTests 1.0
|
||||
|
||||
Item {
|
||||
Extended { }
|
||||
ExtendedIndirect { }
|
||||
ExtendedTwice { }
|
||||
}
|
|
@ -128,6 +128,7 @@ private Q_SLOTS:
|
|||
void groupedPropertySyntax();
|
||||
void attachedProperties();
|
||||
void scriptIndices();
|
||||
void extensions();
|
||||
|
||||
public:
|
||||
tst_qqmljsscope()
|
||||
|
@ -568,5 +569,27 @@ void tst_qqmljsscope::scriptIndices()
|
|||
QCOMPARE(orderedJSScopeExpressionsAbsolute, orderedQmlIrExpressionsAbsolute);
|
||||
}
|
||||
|
||||
void tst_qqmljsscope::extensions()
|
||||
{
|
||||
QQmlJSScope::ConstPtr root = run(u"extensions.qml"_s);
|
||||
QVERIFY(root);
|
||||
QVERIFY(root->isFullyResolved());
|
||||
|
||||
const auto childScopes = root->childScopes();
|
||||
QCOMPARE(childScopes.size(), 3);
|
||||
|
||||
QCOMPARE(childScopes[0]->baseTypeName(), u"Extended"_s);
|
||||
QCOMPARE(childScopes[1]->baseTypeName(), u"ExtendedIndirect"_s);
|
||||
QCOMPARE(childScopes[2]->baseTypeName(), u"ExtendedTwice"_s);
|
||||
QVERIFY(childScopes[0]->isFullyResolved());
|
||||
QVERIFY(childScopes[1]->isFullyResolved());
|
||||
QVERIFY(childScopes[2]->isFullyResolved());
|
||||
|
||||
QCOMPARE(childScopes[0]->property(u"count"_s).typeName(), u"int"_s);
|
||||
QCOMPARE(childScopes[1]->property(u"count"_s).typeName(), u"double"_s);
|
||||
QCOMPARE(childScopes[2]->property(u"count"_s).typeName(), u"int"_s);
|
||||
QCOMPARE(childScopes[2]->property(u"str"_s).typeName(), u"QString"_s);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmljsscope)
|
||||
#include "tst_qqmljsscope.moc"
|
||||
|
|
Loading…
Reference in New Issue