moc: Parse namespaces from other files

We can parse the namespaces in order to find the enums in them and
populate the related metaobjects of the current file's classes. The
symbol clashes are avoided by only generating metaobjects for namespaces
defined in the same file.

Fixes: QTBUG-71966
Fixes: QTBUG-72069
Change-Id: Ibdf21c3f9dae48d95b0952b3e220b4c29e30ecb8
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Ulf Hermann 2019-01-10 13:54:11 +01:00 committed by Simon Hausmann
parent f6cf0442df
commit ae9be1a63d
3 changed files with 30 additions and 17 deletions

View File

@ -565,6 +565,7 @@ void Moc::parse()
} else if (!test(SEMIC)) {
NamespaceDef def;
def.classname = nsName;
def.doGenerate = currentFilenames.size() <= 1;
next(LBRACE);
def.begin = index - 1;
@ -572,25 +573,22 @@ void Moc::parse()
def.end = index;
index = def.begin + 1;
const bool parseNamespace = currentFilenames.size() <= 1;
if (parseNamespace) {
for (int i = namespaceList.size() - 1; i >= 0; --i) {
if (inNamespace(&namespaceList.at(i))) {
def.qualified.prepend(namespaceList.at(i).classname + "::");
}
}
for (const QByteArray &ns : nested) {
NamespaceDef parentNs;
parentNs.classname = ns;
parentNs.qualified = def.qualified;
def.qualified += ns + "::";
parentNs.begin = def.begin;
parentNs.end = def.end;
namespaceList += parentNs;
for (int i = namespaceList.size() - 1; i >= 0; --i) {
if (inNamespace(&namespaceList.at(i))) {
def.qualified.prepend(namespaceList.at(i).classname + "::");
}
}
for (const QByteArray &ns : nested) {
NamespaceDef parentNs;
parentNs.classname = ns;
parentNs.qualified = def.qualified;
def.qualified += ns + "::";
parentNs.begin = def.begin;
parentNs.end = def.end;
namespaceList += parentNs;
}
while (parseNamespace && inNamespace(&def) && hasNext()) {
while (inNamespace(&def) && hasNext()) {
switch (next()) {
case NAMESPACE:
if (test(IDENTIFIER)) {
@ -915,7 +913,8 @@ void Moc::parse()
} else {
knownGadgets.insert(def.classname, def.qualified);
knownGadgets.insert(def.qualified, def.qualified);
classList += def;
if (n.doGenerate)
classList += def;
}
}
}

View File

@ -188,6 +188,7 @@ Q_DECLARE_TYPEINFO(ClassDef::Interface, Q_MOVABLE_TYPE);
struct NamespaceDef : BaseDef {
bool hasQNamespace = false;
bool doGenerate = false;
};
Q_DECLARE_TYPEINFO(NamespaceDef, Q_MOVABLE_TYPE);

View File

@ -3847,6 +3847,14 @@ static void checkEnum(const QMetaEnum &enumerator, const QByteArray &name, const
}
}
class EnumFromNamespaceClass : public QObject
{
Q_OBJECT
Q_PROPERTY(FooNamespace::Enum1 prop READ prop CONSTANT)
public:
FooNamespace::Enum1 prop() { return FooNamespace::Enum1::Key2; }
};
void tst_Moc::testQNamespace()
{
QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 4);
@ -3874,6 +3882,11 @@ void tst_Moc::testQNamespace()
QCOMPARE(FooNamespace::staticMetaObject.enumeratorCount(), 1);
QCOMPARE(FooNamespace::FooNestedNamespace::staticMetaObject.enumeratorCount(), 2);
QCOMPARE(FooNamespace::FooNestedNamespace::FooMoreNestedNamespace::staticMetaObject.enumeratorCount(), 1);
EnumFromNamespaceClass obj;
const QVariant prop = obj.property("prop");
QCOMPARE(prop.type(), QMetaType::Int);
QCOMPARE(prop.toInt(), int(FooNamespace::Enum1::Key2));
}
void tst_Moc::cxx17Namespaces()