From 656d6f2a9b221dbd5adfc46262cb243e696d8d62 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Fri, 12 Apr 2019 13:21:44 +0200 Subject: [PATCH] Support Q_GADGET QMetaObject super class hierarchies across templates This patch fixes the QMetaObject::superClass hierarchy for Q_GADGETs that inherit from a template which in turn inherits another Q_GADGET. One common scenario where this is applied is for the CRTP. Without this patch, moc would stop at the template and then sets the superClass QMetaObject to a nullptr. For QObjects this works, since there moc knows that every child must by definition inherit QObject. In order to support this for Q_GADGETs too, we defer the judgment about the availability of a staticMetaObject in the base class to compile time through the existing QtPrivate::MetaObjectForType::value() helper. [ChangeLog][QtCore][moc] Moc now correctly sets a non-null QMetaObject::superClass for Q_GADGETs that inherit from a template which inherits another Q_GADGET. Change-Id: I103b5efd74ed24172dffce477ca2ed6d0f374d44 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/tools/moc/generator.cpp | 4 +++- tests/auto/tools/moc/allmocs_baseline_in.json | 11 +++++++++++ tests/auto/tools/moc/grand-parent-gadget-class.h | 3 ++- tests/auto/tools/moc/tst_moc.cpp | 1 + 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 553e16d472..9029bf9008 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -541,8 +541,10 @@ void Generator::generateCode() if (isQObject) fprintf(out, " nullptr,\n"); - else if (cdef->superclassList.size() && (!cdef->hasQGadget || knownGadgets.contains(purestSuperClass))) + else if (cdef->superclassList.size() && !cdef->hasQGadget) // for qobject, we know the super class must have a static metaobject fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", purestSuperClass.constData()); + else if (cdef->superclassList.size()) // for gadgets we need to query at compile time for it + fprintf(out, " QtPrivate::MetaObjectForType<%s>::value(),\n", purestSuperClass.constData()); else fprintf(out, " nullptr,\n"); fprintf(out, " qt_meta_stringdata_%s.data,\n" diff --git a/tests/auto/tools/moc/allmocs_baseline_in.json b/tests/auto/tools/moc/allmocs_baseline_in.json index bde5a1c52b..8cb397190c 100644 --- a/tests/auto/tools/moc/allmocs_baseline_in.json +++ b/tests/auto/tools/moc/allmocs_baseline_in.json @@ -2061,6 +2061,17 @@ "name": "Derived" } ] + }, + { + "className": "CRTPDerivedGadget", + "gadget": true, + "qualifiedClassName": "GrandParentGadget::CRTPDerivedGadget", + "superClasses": [ + { + "access": "public", + "name": "CRTP" + } + ] } ], "inputFile": "grand-parent-gadget-class.h", diff --git a/tests/auto/tools/moc/grand-parent-gadget-class.h b/tests/auto/tools/moc/grand-parent-gadget-class.h index 7ffd636ca1..c7720a1ab9 100644 --- a/tests/auto/tools/moc/grand-parent-gadget-class.h +++ b/tests/auto/tools/moc/grand-parent-gadget-class.h @@ -36,7 +36,8 @@ namespace GrandParentGadget { struct BaseGadget { Q_GADGET }; struct Derived : BaseGadget {}; struct DerivedGadget : Derived { Q_GADGET }; - +template struct CRTP : BaseGadget {}; +struct CRTPDerivedGadget : CRTP { Q_GADGET }; } #endif // GRANDPARENTGADGETCLASS_H diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 9fc00288fe..6b202f79a6 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -3836,6 +3836,7 @@ void tst_Moc::gadgetHierarchy() { QCOMPARE(NonGadgetParent::Derived::staticMetaObject.superClass(), static_cast(nullptr)); QCOMPARE(GrandParentGadget::DerivedGadget::staticMetaObject.superClass(), &GrandParentGadget::BaseGadget::staticMetaObject); + QCOMPARE(GrandParentGadget::CRTPDerivedGadget::staticMetaObject.superClass(), &GrandParentGadget::BaseGadget::staticMetaObject); } void tst_Moc::optionsFileError_data()