diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 190f4e139d..0e38f2a2bf 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -2694,10 +2694,14 @@ int QMetaProperty::userType() const if (type != QMetaType::UnknownType) return type; if (isEnumType()) { - int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); - if (enumMetaTypeId == QMetaType::UnknownType) - return QVariant::Int; // Match behavior of QMetaType::type() - return enumMetaTypeId; + type = QMetaType::type(qualifiedName(menum)); + if (type == QMetaType::UnknownType) { + void *argv[] = { &type }; + mobj->static_metacall(QMetaObject::RegisterPropertyMetaType, idx, argv); + if (type == -1 || type == QMetaType::UnknownType) + return QVariant::Int; // Match behavior of QMetaType::type() + } + return type; } type = QMetaType::type(typeName()); if (type != QMetaType::UnknownType) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index b688400cd4..0740a860ba 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -87,7 +87,7 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING) return 0; } -Generator::Generator(ClassDef *classDef, const QList &metaTypes, const QSet &knownQObjectClasses, FILE *outfile) +Generator::Generator(ClassDef *classDef, const QList &metaTypes, const QHash &knownQObjectClasses, FILE *outfile) : out(outfile), cdef(classDef), metaTypes(metaTypes), knownQObjectClasses(knownQObjectClasses) { if (cdef->superclassList.size()) @@ -438,15 +438,31 @@ void Generator::generateCode() QList extraList; for (int i = 0; i < cdef->propertyList.count(); ++i) { const PropertyDef &p = cdef->propertyList.at(i); - if (!isBuiltinType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') && - !p.type.contains('<') && !p.type.contains('>')) { - int s = p.type.lastIndexOf("::"); - if (s > 0) { - QByteArray scope = p.type.left(s); - if (scope != "Qt" && !qualifiedNameEquals(cdef->qualified, scope) && !extraList.contains(scope)) - extraList += scope; - } - } + if (isBuiltinType(p.type)) + continue; + + if (p.type.contains('*') || p.type.contains('<') || p.type.contains('>')) + continue; + + int s = p.type.lastIndexOf("::"); + if (s <= 0) + continue; + + QByteArray unqualifiedScope = p.type.left(s); + + // The scope may be a namespace for example, so it's only safe to include scopes that are known QObjects (QTBUG-2151) + QHash::ConstIterator scopeIt = knownQObjectClasses.find(unqualifiedScope); + if (scopeIt == knownQObjectClasses.constEnd()) + continue; + const QByteArray &scope = *scopeIt; + + if (scope == "Qt") + continue; + if (qualifiedNameEquals(cdef->qualified, scope)) + continue; + + if (!extraList.contains(scope)) + extraList += scope; } // QTBUG-20639 - Accept non-local enums for QML signal/slot parameters. diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h index 203c856b7c..725c4ffb12 100644 --- a/src/tools/moc/generator.h +++ b/src/tools/moc/generator.h @@ -52,7 +52,7 @@ class Generator ClassDef *cdef; QVector meta_data; public: - Generator(ClassDef *classDef, const QList &metaTypes, const QSet &knownQObjectClasses, FILE *outfile = 0); + Generator(ClassDef *classDef, const QList &metaTypes, const QHash &knownQObjectClasses, FILE *outfile = 0); void generateCode(); private: bool registerableMetaType(const QByteArray &propertyType); @@ -79,7 +79,7 @@ private: QList strings; QByteArray purestSuperClass; QList metaTypes; - QSet knownQObjectClasses; + QHash knownQObjectClasses; }; QT_END_NAMESPACE diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 8ff481d5b1..15b65d2045 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -621,8 +621,8 @@ void Moc::parse() if (inNamespace(&namespaceList.at(i))) def.qualified.prepend(namespaceList.at(i).name + "::"); - knownQObjectClasses.insert(def.classname); - knownQObjectClasses.insert(def.qualified); + knownQObjectClasses.insert(def.classname, def.qualified); + knownQObjectClasses.insert(def.qualified, def.qualified); continue; } default: break; @@ -795,8 +795,8 @@ void Moc::parse() checkProperties(&def); classList += def; - knownQObjectClasses.insert(def.classname); - knownQObjectClasses.insert(def.qualified); + knownQObjectClasses.insert(def.classname, def.qualified); + knownQObjectClasses.insert(def.qualified, def.qualified); } } } diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 2e22435653..4bbdde47dc 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -215,7 +215,8 @@ public: QList classList; QMap interface2IdMap; QList metaTypes; - QSet knownQObjectClasses; + // map from class name to fully qualified name + QHash knownQObjectClasses; QMap metaArgs; void parse(); diff --git a/tests/auto/tools/moc/moc.pro b/tests/auto/tools/moc/moc.pro index 779e992881..c68d48b813 100644 --- a/tests/auto/tools/moc/moc.pro +++ b/tests/auto/tools/moc/moc.pro @@ -24,7 +24,8 @@ HEADERS += using-namespaces.h no-keywords.h task87883.h c-comments.h backslash-n parse-defines.h \ function-with-attributes.h \ plugin_metadata.h \ - single-quote-digit-separator-n3781.h + single-quote-digit-separator-n3781.h \ + related-metaobjects-in-namespaces.h if(*-g++*|*-icc*|*-clang*|*-llvm):!irix-*:!win32-*: HEADERS += os9-newlines.h win-newlines.h diff --git a/tests/auto/tools/moc/related-metaobjects-in-namespaces.h b/tests/auto/tools/moc/related-metaobjects-in-namespaces.h new file mode 100644 index 0000000000..0a3e9ed77d --- /dev/null +++ b/tests/auto/tools/moc/related-metaobjects-in-namespaces.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +namespace QTBUG_2151 { + class A : public QObject { + Q_OBJECT + Q_ENUMS(SomeEnum) + public: + enum SomeEnum { SomeEnumValue = 0 }; + }; + + class B : public QObject + { + Q_OBJECT + Q_PROPERTY(A::SomeEnum blah READ blah) + public: + + A::SomeEnum blah() const { return A::SomeEnumValue; } + }; +} diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 0b4560341e..46f3e5a42a 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -76,6 +76,7 @@ #include "cxx11-explicit-override-control.h" #include "parse-defines.h" +#include "related-metaobjects-in-namespaces.h" QT_USE_NAMESPACE @@ -568,6 +569,8 @@ private slots: void preprocessorOnly(); void unterminatedFunctionMacro(); void QTBUG32933_relatedObjectsDontIncludeItself(); + void writeEnumFromUnrelatedClass(); + void relatedMetaObjectsWithinNamespaces(); signals: void sigWithUnsignedArg(unsigned foo); @@ -3104,6 +3107,61 @@ void tst_Moc::QTBUG32933_relatedObjectsDontIncludeItself() } +class UnrelatedClass : public QObject +{ + Q_OBJECT + Q_ENUMS(UnrelatedEnum) +public: + enum UnrelatedEnum { + UnrelatedInvalidValue = -1, + UnrelatedValue = 42 + }; +}; + +// The presence of this macro used to confuse moc and prevent +// UnrelatedClass from being listed in the related meta objects. +Q_DECLARE_METATYPE(UnrelatedClass::UnrelatedEnum) + +class TestClassReferencingUnrelatedEnum : public QObject +{ + Q_OBJECT + Q_PROPERTY(UnrelatedClass::UnrelatedEnum enumProperty READ enumProperty WRITE setEnumProperty) +public: + TestClassReferencingUnrelatedEnum() + : m_enumProperty(UnrelatedClass::UnrelatedInvalidValue) + {} + + UnrelatedClass::UnrelatedEnum enumProperty() const { + return m_enumProperty; + } + + void setEnumProperty(UnrelatedClass::UnrelatedEnum arg) { + m_enumProperty = arg; + } + +private: + UnrelatedClass::UnrelatedEnum m_enumProperty; +}; + +void tst_Moc::writeEnumFromUnrelatedClass() +{ + TestClassReferencingUnrelatedEnum obj; + QString enumValueAsString("UnrelatedValue"); + obj.setProperty("enumProperty", enumValueAsString); + QCOMPARE(int(obj.enumProperty()), int(UnrelatedClass::UnrelatedValue)); +} + + + +void tst_Moc::relatedMetaObjectsWithinNamespaces() +{ + const QMetaObject *relatedMo = &QTBUG_2151::A::staticMetaObject; + + const QMetaObject *testMo = &QTBUG_2151::B::staticMetaObject; + QVERIFY(testMo->d.relatedMetaObjects); + QVERIFY(testMo->d.relatedMetaObjects[0] == relatedMo); +} + QTEST_MAIN(tst_Moc) // the generated code must compile with QT_NO_KEYWORDS