From 351b7a31aa24a704dba09121d91cb34190892315 Mon Sep 17 00:00:00 2001 From: Matthias Rauter Date: Tue, 18 Feb 2025 17:20:09 +0100 Subject: [PATCH] Add namespaces to qdbusxml2cpp [ChangeLog][QtDBus][qdbusxml2cpp] The Qt D-Bus XML compiler (qdbusxml2cpp) now supports the command-line argument -namespace , which encapsulates all generated classes within the specified namespace to prevent class name conflicts. Fixes: QTBUG-133611 Change-Id: Ic3473dfc33dcf22f5be727236fe546b70b2b015b Reviewed-by: Ivan Solovev --- src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp | 41 +++++++++++++++- .../tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp | 47 +++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp index d637854d2bb..7ab7241c962 100644 --- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp +++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp @@ -80,6 +80,7 @@ private: QString globalClassName; QString parentClassName; + QString customNamespace; QString inputFile; bool skipNamespaces = false; bool includeMocs = false; @@ -608,6 +609,13 @@ void QDBusXmlToCpp::writeProxy(const QString &filename, cs << "#include \"" << headerName << "\"\n\n"; } + if (!customNamespace.isEmpty()) { + hs << "namespace " << customNamespace << " { \n" + "\n"; + cs << "namespace " << customNamespace << " { \n" + "\n"; + } + for (const QDBusIntrospection::Interface *interface : interfaces) { QString className = classNameForInterface(interface->name, Proxy); @@ -799,6 +807,13 @@ void QDBusXmlToCpp::writeProxy(const QString &filename, hs << "};\n\n"; } + if (!customNamespace.isEmpty()) { + hs << "} // end of namespace " << customNamespace << "\n" + << "\n"; + cs << "} // end of namespace " << customNamespace << "\n" + << "\n"; + } + if (!skipNamespaces) { QStringList last; QDBusIntrospection::Interfaces::ConstIterator it = interfaces.constBegin(); @@ -827,7 +842,8 @@ void QDBusXmlToCpp::writeProxy(const QString &filename, // add this class: if (!name.isEmpty()) { hs << QString(current.size() * 2, u' ') - << "using " << name << " = ::" << classNameForInterface(it->constData()->name, Proxy) + << "using " << name << " = " << (customNamespace.isEmpty() ? "" : "::") + << customNamespace << "::" << classNameForInterface(it->constData()->name, Proxy) << ";\n"; } @@ -836,6 +852,8 @@ void QDBusXmlToCpp::writeProxy(const QString &filename, ++it; last = current; } while (true); + + hs << "\n"; } // close the include guard @@ -937,6 +955,13 @@ void QDBusXmlToCpp::writeAdaptor(const QString &filename, if (parentClassName.isEmpty()) parent = u"QObject"_s; + if (!customNamespace.isEmpty()) { + hs << "namespace " << customNamespace << " { \n" + "\n"; + cs << "namespace " << customNamespace << " { \n" + "\n"; + } + for (const QDBusIntrospection::Interface *interface : interfaces) { QString className = classNameForInterface(interface->name, Adaptor); @@ -1134,6 +1159,13 @@ void QDBusXmlToCpp::writeAdaptor(const QString &filename, hs << "};\n\n"; } + if (!customNamespace.isEmpty()) { + hs << "} // end of namespace " << customNamespace << "\n" + << "\n"; + cs << "} // end of namespace " << customNamespace << "\n" + << "\n"; + } + // close the include guard hs << "#endif\n"; @@ -1188,6 +1220,10 @@ int QDBusXmlToCpp::run(const QCoreApplication &app) u"classname"_s); parser.addOption(classNameOption); + QCommandLineOption namespaceOption(QStringList{u"namespace"_s}, + u"Put all generated classes into the namespace . "_s, u"namespace"_s); + parser.addOption(namespaceOption); + QCommandLineOption addIncludeOption(QStringList{u"i"_s, u"include"_s}, u"Add #include \"filename\" to the output"_s, u"filename"_s); parser.addOption(addIncludeOption); @@ -1205,7 +1241,7 @@ int QDBusXmlToCpp::run(const QCoreApplication &app) parser.addOption(mocIncludeOption); QCommandLineOption noNamespaceOption(QStringList{u"N"_s, u"no-namespaces"_s}, - u"Don't use namespaces"_s); + u"Do not export the generated class into the D-Bus specific namespace"_s); parser.addOption(noNamespaceOption); QCommandLineOption proxyCodeOption(QStringList{u"p"_s, u"proxy"_s}, @@ -1223,6 +1259,7 @@ int QDBusXmlToCpp::run(const QCoreApplication &app) includes = parser.values(addIncludeOption); globalIncludes = parser.values(addGlobalIncludeOption); parentClassName = parser.value(adapterParentOption); + customNamespace = parser.value(namespaceOption); includeMocs = parser.isSet(mocIncludeOption); skipNamespaces = parser.isSet(noNamespaceOption); QString proxyFile = parser.value(proxyCodeOption); diff --git a/tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp b/tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp index c51a0909f8d..5474c4f7470 100644 --- a/tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp +++ b/tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp @@ -25,6 +25,8 @@ private slots: void missingAnnotation(); void includeMoc_data(); void includeMoc(); + void customNamespace_data(); + void customNamespace(); }; struct BasicTypeList { @@ -482,6 +484,51 @@ void tst_qdbusxml2cpp::includeMoc() } } +void tst_qdbusxml2cpp::customNamespace_data() +{ + QTest::addColumn("namesp"); + + QTest::newRow("simple") << QByteArray("lancetest"); + QTest::newRow("double") << QByteArray("lance::test"); +} + +void tst_qdbusxml2cpp::customNamespace() +{ + QFETCH(QByteArray, namesp); + + QProcess process; + QStringList flags = {"-", "--namespace", namesp}; + + runTool(process,QByteArray{},flags); + QCOMPARE(process.exitCode(), 0); + + QByteArray errOutput = process.readAllStandardError(); + QVERIFY2(errOutput.isEmpty(), errOutput); + + QByteArray fullOutput = process.readAll(); + QVERIFY(!fullOutput.isEmpty()); + + // twice: once in the header, once in the implementation + static constexpr qsizetype requiredNameSpaceCount = 2; + QCOMPARE(fullOutput.count("namespace " + namesp + " {"), requiredNameSpaceCount); + + static constexpr QByteArrayView endMarker("} // end of namespace "); + qsizetype startFrom = 0; + for (qsizetype i = 0; i < requiredNameSpaceCount; ++i) { + // make sure the namespace is there + qsizetype namespaceStart = fullOutput.indexOf("namespace " + namesp + " {", startFrom); + qsizetype namespaceEnd = fullOutput.indexOf(endMarker + namesp, namespaceStart); + QCOMPARE_GE(namespaceStart, 0); + QCOMPARE_GT(namespaceEnd, namespaceStart); + startFrom = namespaceEnd + endMarker.size() + namesp.size(); + + // make sure we cover a useful part of the source code with the namespace: + auto partOutput = QByteArrayView(fullOutput) + .slice(namespaceStart, startFrom - namespaceStart); + QCOMPARE(partOutput.count("{"), partOutput.count("}")); + } +} + QTEST_MAIN(tst_qdbusxml2cpp) #include "tst_qdbusxml2cpp.moc"