From de725afd153cc7eb1930d4820abbbcff889bd04c Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 5 Jul 2017 12:57:32 +0200 Subject: [PATCH] Allow NOTIFY signals defined in parent classes Implemented in Qt 5.10 by commit 2ca187caa383ddc0cdebeb1dbc312405c8c871ad --- src/generator.cpp | 14 ++++++++++---- src/mocng.cpp | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/generator.cpp b/src/generator.cpp index e7a7f34..beb3b40 100644 --- a/src/generator.cpp +++ b/src/generator.cpp @@ -1074,12 +1074,12 @@ void Generator::GenerateStaticMetaCall() } else if (!p.member.empty()) { std::string M = Prefix + p.member; std::string A = "*reinterpret_cast< " + p.type + "*>(_a[0])"; - if (p.notify.notifyId >= 0) { + if (!p.notify.Str.empty()) { OS_TemplateHeader << "\n" " if (" << M << " != " << A << ") {\n" " " << M << " = " << A << ";\n" " Q_EMIT _t->" << p.notify.Str << "("; - if (p.notify.MD->getMinRequiredArguments() > 0) + if (p.notify.MD && p.notify.MD->getMinRequiredArguments() > 0) OS_TemplateHeader << M; OS_TemplateHeader << ");\n" " } "; @@ -1234,7 +1234,7 @@ void Generator::GenerateProperties() flags |= ResolveUser; else if (p.user != "false") flags |= User; - if (p.notify.notifyId != -1) + if (!p.notify.Str.empty()) flags |= Notify; if (p.revision > 0) flags |= Revisioned; @@ -1249,7 +1249,13 @@ void Generator::GenerateProperties() if(CDef->NotifyCount) { OS << "\n // properties: notify_signal_id\n"; for (const PropertyDef &P : CDef->Properties) { - OS << " " << std::max(0, P.notify.notifyId) << ",\n"; + if (P.notify.notifyId >= 0) { + OS << " " << P.notify.notifyId << ",\n"; + } else if (!P.notify.Str.empty()) { + OS << " 0x70000000 | " << StrIdx(P.notify.Str) << ",\n"; + } else { + OS << " 0,\n"; + } } } diff --git a/src/mocng.cpp b/src/mocng.cpp index d39174c..1ca4375 100644 --- a/src/mocng.cpp +++ b/src/mocng.cpp @@ -449,6 +449,7 @@ ClassDef MocNg::parseClass(clang::CXXRecordDecl* RD, clang::Sema& Sema) for (PropertyDef &P: Def.Properties) { if (!P.notify.Str.empty()) { int Idx = 0; + auto errorLevel = clang::DiagnosticsEngine::Error; for (clang::CXXMethodDecl *MD : Def.Signals) { if (MD->getName() == P.notify.Str) { P.notify.notifyId = Idx; @@ -458,13 +459,43 @@ ClassDef MocNg::parseClass(clang::CXXRecordDecl* RD, clang::Sema& Sema) Idx += 1 + MD->getNumParams() - MD->getMinRequiredArguments(); } if (P.notify.notifyId < 0 ) { + // Search in base classes + clang::CXXRecordDecl *Base = Def.Record; + do { + if (!Base->getNumBases()) + break; + Base = Base->bases_begin()->getType()->getAsCXXRecordDecl(); + if (!Base) + break; + for (auto it = Base->decls_begin(); it != Base->decls_end(); ++it) { + if (auto *MD = llvm::dyn_cast(*it)) { + + if (MD->getIdentifier() && MD->getName() == P.notify.Str) { + // We found a possible match. Check if it is indeed a signal + if (std::any_of(MD->specific_attr_begin(), + MD->specific_attr_end(), + [&](const clang::AnnotateAttr *a) { + return a->getAnnotation() == "qt_signal"; + })) { + P.notify.MD = MD; + break; + } + // Since the official moc let this compile and the runtime will show + // a warning, we just change the level to Warning. + // (required for tst_qmetaobject which tests that) + errorLevel = clang::DiagnosticsEngine::Warning; + } + } + } + } while(!P.notify.MD); + } + if (!P.notify.MD) { PP.getDiagnostics().Report(P.notify.Loc, - PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, - "NOTIFY signal '%0' of property '%1' does not exist in class %2")) + PP.getDiagnostics().getCustomDiagID(errorLevel, + "NOTIFY signal '%0' of property '%1' does not exist in class %2")) << P.notify.Str << P.name << Def.Record; - } else { - Def.NotifyCount++; } + Def.NotifyCount++; } if (P.revision > 0)