summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qmetatype.cpp63
-rw-r--r--src/corelib/kernel/qmetatype.h1
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp48
3 files changed, 106 insertions, 6 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index d4a69ee4b9..3b70ef92ed 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -872,13 +872,17 @@ static inline int qMetaTypeStaticType(const char *typeName, int length)
\internal
Similar to QMetaType::type(), but only looks in the custom set of
types, and doesn't lock the mutex.
+ The extra \a firstInvalidIndex parameter is an easy way to avoid
+ iterating over customTypes() a second time in registerNormalizedType().
*/
-static int qMetaTypeCustomType_unlocked(const char *typeName, int length)
+static int qMetaTypeCustomType_unlocked(const char *typeName, int length, int *firstInvalidIndex = 0)
{
const QVector<QCustomTypeInfo> * const ct = customTypes();
if (!ct)
return QMetaType::UnknownType;
+ if (firstInvalidIndex)
+ *firstInvalidIndex = -1;
for (int v = 0; v < ct->count(); ++v) {
const QCustomTypeInfo &customInfo = ct->at(v);
if ((length == customInfo.typeName.size())
@@ -887,6 +891,8 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length)
return customInfo.alias;
return v + QMetaType::User;
}
+ if (firstInvalidIndex && (*firstInvalidIndex < 0) && customInfo.typeName.isEmpty())
+ *firstInvalidIndex = v;
}
return QMetaType::UnknownType;
}
@@ -907,6 +913,39 @@ int QMetaType::registerType(const char *typeName, Deleter deleter,
/*!
\internal
+ \since 5.5
+
+ Unregisters the user type with the given \a typeId and all its aliases.
+ Returns \c true if the type was unregistered or \c false otherwise.
+
+ This function was added for QML to be able to deregister types after
+ they are unloaded to prevent an infinite increase in custom types for
+ applications that are unloading/reloading components often.
+ */
+bool QMetaType::unregisterType(int type)
+{
+ QWriteLocker locker(customTypesLock());
+ QVector<QCustomTypeInfo> *ct = customTypes();
+
+ // check if user type
+ if ((type < User) || ((type - User) >= ct->size()))
+ return false;
+
+ // only types without Q_DECLARE_METATYPE can be unregistered
+ if (ct->data()[type - User].flags & WasDeclaredAsMetaType)
+ return false;
+
+ // invalidate type and all its alias entries
+ for (int v = 0; v < ct->count(); ++v) {
+ if (((v + User) == type) || (ct->at(v).alias == type))
+ ct->data()[v].typeName.clear();
+ }
+ return true;
+}
+
+
+/*!
+ \internal
\since 5.0
Registers a user type for marshalling, with \a typeName, a \a
@@ -977,8 +1016,10 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
int previousFlags = 0;
if (idx == UnknownType) {
QWriteLocker locker(customTypesLock());
+ int posInVector = -1;
idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
- normalizedTypeName.size());
+ normalizedTypeName.size(),
+ &posInVector);
if (idx == UnknownType) {
QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
@@ -992,8 +1033,13 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
inf.size = size;
inf.flags = flags;
inf.metaObject = metaObject;
- idx = ct->size() + User;
- ct->append(inf);
+ if (posInVector == -1) {
+ idx = ct->size() + User;
+ ct->append(inf);
+ } else {
+ idx = posInVector + User;
+ ct->data()[posInVector] = inf;
+ }
return idx;
}
@@ -1075,14 +1121,19 @@ int QMetaType::registerNormalizedTypedef(const NS(QByteArray) &normalizedTypeNam
if (idx == UnknownType) {
QWriteLocker locker(customTypesLock());
+ int posInVector = -1;
idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
- normalizedTypeName.size());
+ normalizedTypeName.size(),
+ &posInVector);
if (idx == UnknownType) {
QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
inf.alias = aliasId;
- ct->append(inf);
+ if (posInVector == -1)
+ ct->append(inf);
+ else
+ ct->data()[posInVector] = inf;
return aliasId;
}
}
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index aa8d826ed9..1e2a860d8c 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -484,6 +484,7 @@ public:
int size,
QMetaType::TypeFlags flags,
const QMetaObject *metaObject);
+ static bool unregisterType(int type);
static int registerNormalizedType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, Deleter deleter,
Creator creator,
Destructor destructor,
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
index 88b1bebb29..b3333c6d68 100644
--- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
+++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
@@ -1254,6 +1254,54 @@ void tst_QMetaType::registerType()
QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
QCOMPARE(QMetaType::type("MyFoo"), fooId);
+
+ // cannot unregister built-in types
+ QVERIFY(!QMetaType::unregisterType(QMetaType::QString));
+ QCOMPARE(QMetaType::type("QString"), int(QMetaType::QString));
+ QCOMPARE(QMetaType::type("MyString"), int(QMetaType::QString));
+
+ // cannot unregister declared types
+ QVERIFY(!QMetaType::unregisterType(fooId));
+ QCOMPARE(QMetaType::type("TestSpace::Foo"), fooId);
+ QCOMPARE(QMetaType::type("MyFoo"), fooId);
+
+ // test unregistration of dynamic types (used by Qml)
+ int unregId = QMetaType::registerType("UnregisterMe",
+ 0,
+ 0,
+ QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
+ QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
+ 0, QMetaType::TypeFlags(), 0);
+ QCOMPARE(QMetaType::registerTypedef("UnregisterMeTypedef", unregId), unregId);
+ int unregId2 = QMetaType::registerType("UnregisterMe2",
+ 0,
+ 0,
+ QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
+ QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
+ 0, QMetaType::TypeFlags(), 0);
+ QVERIFY(unregId >= int(QMetaType::User));
+ QCOMPARE(unregId2, unregId + 2);
+
+ QVERIFY(QMetaType::unregisterType(unregId));
+ QCOMPARE(QMetaType::type("UnregisterMe"), 0);
+ QCOMPARE(QMetaType::type("UnregisterMeTypedef"), 0);
+ QCOMPARE(QMetaType::type("UnregisterMe2"), unregId2);
+ QVERIFY(QMetaType::unregisterType(unregId2));
+ QCOMPARE(QMetaType::type("UnregisterMe2"), 0);
+
+ // re-registering should always return the lowest free index
+ QCOMPARE(QMetaType::registerType("UnregisterMe2",
+ 0,
+ 0,
+ QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
+ QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
+ 0, QMetaType::TypeFlags(), 0), unregId);
+ QCOMPARE(QMetaType::registerType("UnregisterMe",
+ 0,
+ 0,
+ QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
+ QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
+ 0, QMetaType::TypeFlags(), 0), unregId + 1);
}
class IsRegisteredDummyType { };