Add namespaces to qdbusxml2cpp

[ChangeLog][QtDBus][qdbusxml2cpp] The Qt D-Bus XML compiler
(qdbusxml2cpp) now supports the command-line argument -namespace
<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 <ivan.solovev@qt.io>
This commit is contained in:
Matthias Rauter 2025-02-18 17:20:09 +01:00
parent 611031e4f0
commit 351b7a31aa
2 changed files with 86 additions and 2 deletions

View File

@ -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 <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);

View File

@ -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<QByteArray>("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"