mirror of https://github.com/qt/qtgrpc.git
generator: handle invalid identifier(s) in filename
The generation was broken for proto filenames, which where invalid identifier, since the filename is used at several places in the generation process. This became evident for the protobuftyperegistrations and traditional filename header guards. Solve this by transforming the basename into a valid identifier. Also add a testcase on the highest point of abstraction for the generators (qtgrpcgen). Fixes: QTBUG-131417 Pick-to: 6.8 Change-Id: I492907881913f8b43ebf365a9e1fe38062113c3c Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
parent
aa70a1099c
commit
4a3fc66b89
|
@ -176,6 +176,7 @@ bool QGrpcGenerator::GenerateClientServices(const FileDescriptor *file,
|
|||
|
||||
const std::string basename = utils::extractFileBasename(file->name()) +
|
||||
GrpcTemplates::GrpcClientFileSuffix() + CommonTemplates::ProtoFileSuffix();
|
||||
std::string identifier = utils::toValidIdentifier(basename);
|
||||
const std::string realtivePath = common::generateRelativeFilePath(file, basename);
|
||||
|
||||
// Generate QML class
|
||||
|
@ -195,7 +196,7 @@ bool QGrpcGenerator::GenerateClientServices(const FileDescriptor *file,
|
|||
printDisclaimer(clientSourcePrinter.get());
|
||||
|
||||
const std::string
|
||||
headerGuard = common::headerGuardFromFilename(basename + CommonTemplates::HeaderSuffix());
|
||||
headerGuard = common::headerGuardFromFilename(identifier + CommonTemplates::HeaderSuffix());
|
||||
QGrpcGenerator::printHeaderGuardBegin(clientHeaderPrinter.get(), headerGuard);
|
||||
|
||||
clientSourcePrinter->Print(
|
||||
|
|
|
@ -48,6 +48,7 @@ void QProtobufGenerator::GenerateSources(const FileDescriptor *file,
|
|||
assert(generatorContext != nullptr);
|
||||
|
||||
std::string basename = utils::extractFileBasename(file->name());
|
||||
std::string identifier = utils::toValidIdentifier(basename);
|
||||
std::string relativePath = common::generateRelativeFilePath(file, basename);
|
||||
std::unique_ptr<io::ZeroCopyOutputStream> sourceStream(
|
||||
generatorContext->Open(relativePath + CommonTemplates::ProtoFileSuffix() + ".cpp"));
|
||||
|
@ -92,7 +93,7 @@ void QProtobufGenerator::GenerateSources(const FileDescriptor *file,
|
|||
messageDef.printClassRegistration(registrationPrinter.get());
|
||||
});
|
||||
|
||||
registrationPrinter->Print({{"proto_name", utils::capitalizeAsciiName(basename)}},
|
||||
registrationPrinter->Print({{"proto_name", utils::capitalizeAsciiName(identifier)}},
|
||||
CommonTemplates::ProtobufTypeRegistrarTemplate());
|
||||
|
||||
CloseFileNamespaces(file, registrationPrinter.get());
|
||||
|
@ -113,6 +114,7 @@ void QProtobufGenerator::GenerateHeader(const FileDescriptor *file,
|
|||
|
||||
const std::string basename = utils::extractFileBasename(file->name()) +
|
||||
CommonTemplates::ProtoFileSuffix();
|
||||
std::string identifier = utils::toValidIdentifier(basename);
|
||||
std::string relativePath = common::generateRelativeFilePath(file, basename);
|
||||
|
||||
std::unique_ptr<io::ZeroCopyOutputStream>
|
||||
|
@ -126,7 +128,7 @@ void QProtobufGenerator::GenerateHeader(const FileDescriptor *file,
|
|||
std::set<std::string> systemIncludes;
|
||||
|
||||
const std::string
|
||||
headerGuard = common::headerGuardFromFilename(basename + CommonTemplates::HeaderSuffix());
|
||||
headerGuard = common::headerGuardFromFilename(identifier + CommonTemplates::HeaderSuffix());
|
||||
QProtobufGenerator::printHeaderGuardBegin(headerPrinter.get(), headerGuard);
|
||||
if (!Options::instance().exportMacroFilename().empty()) {
|
||||
std::string exportMacroFilename = Options::instance().exportMacroFilename();
|
||||
|
|
|
@ -21,6 +21,11 @@ bool isAsciiAlpha(char c)
|
|||
return (unsigned char)c <= 127 && ::isalpha(c);
|
||||
}
|
||||
|
||||
bool isAsciiAlnum(char c)
|
||||
{
|
||||
return (unsigned char)c <= 127 && std::isalnum(c);
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string_view s, std::string_view c, bool keepEmpty)
|
||||
{
|
||||
assert(!c.empty());
|
||||
|
@ -89,6 +94,25 @@ std::string extractFileBasename(std::string fileName)
|
|||
return slash != std::string::npos ? fileName.substr(slash + 1) : fileName;
|
||||
}
|
||||
|
||||
std::string toValidIdentifier(std::string_view name)
|
||||
{
|
||||
assert(!name.empty() && "empty names are not supported as identifier");
|
||||
std::string out;
|
||||
out.reserve(name.size() + 1);
|
||||
|
||||
if (!isAsciiAlpha(name[0]) && name[0] != '_') // omitted Unicode with XID_Start
|
||||
out += '_';
|
||||
|
||||
for (const auto c : name) {
|
||||
if (isAsciiAlnum(c) || c == '_') // omitted Unicode with XID_Continue
|
||||
out += c;
|
||||
else
|
||||
out += '_'; // TODO: a deterministic hex - ASCII mapping algorithm would be better
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string capitalizeAsciiName(std::string name)
|
||||
{
|
||||
if (name.empty() || !isAsciiAlpha(name[0]))
|
||||
|
|
|
@ -29,6 +29,7 @@ void asciiToLower(std::string &str);
|
|||
void asciiToUpper(std::string &str);
|
||||
std::string removeFileSuffix(std::string fileName);
|
||||
std::string extractFileBasename(std::string fileName);
|
||||
std::string toValidIdentifier(std::string_view name);
|
||||
std::string capitalizeAsciiName(std::string name);
|
||||
std::string deCapitalizeAsciiName(std::string name);
|
||||
std::string &rtrim(std::string &s);
|
||||
|
|
|
@ -57,6 +57,24 @@ target_include_directories(tst_qtgrpcgen_no_options PRIVATE
|
|||
"${CMAKE_CURRENT_BINARY_DIR}/${cmake_generated_dir}/protobuf_common/qtgrpc/tests")
|
||||
list(APPEND cmake_generator_tests no_options)
|
||||
|
||||
qt_add_protobuf(tst_qtgrpcgen_protobuf_invalid-identifier
|
||||
PROTO_FILES
|
||||
data/666-invalid-identifier.proto
|
||||
HEADER_GUARD filename
|
||||
OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${cmake_generated_dir}/invalid-identifier"
|
||||
)
|
||||
qt_add_grpc(tst_qtgrpcgen_invalid-identifier CLIENT
|
||||
PROTO_FILES
|
||||
data/666-invalid-identifier.proto
|
||||
HEADER_GUARD filename
|
||||
OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${cmake_generated_dir}/invalid-identifier"
|
||||
)
|
||||
target_link_libraries(tst_qtgrpcgen_invalid-identifier
|
||||
PRIVATE tst_qtgrpcgen_protobuf_invalid-identifier)
|
||||
list(APPEND cmake_generator_tests invalid-identifier)
|
||||
|
||||
if(TARGET Qt6::GrpcQuick)
|
||||
qt_internal_extend_target(tst_qtgrpcgen
|
||||
DEFINES
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
syntax = "proto3";
|
||||
|
||||
message Empty {}
|
||||
|
||||
service InvalidService {
|
||||
rpc Get(Empty) returns (Empty) {}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
|
||||
|
||||
|
||||
#include "666-invalid-identifier.qpb.h"
|
||||
|
||||
#include <QtProtobuf/qprotobufregistration.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
class Empty_QtProtobufData : public QSharedData
|
||||
{
|
||||
public:
|
||||
Empty_QtProtobufData()
|
||||
: QSharedData()
|
||||
{
|
||||
}
|
||||
|
||||
Empty_QtProtobufData(const Empty_QtProtobufData &other)
|
||||
: QSharedData(other)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Empty::~Empty() = default;
|
||||
|
||||
static constexpr struct {
|
||||
QtProtobufPrivate::QProtobufPropertyOrdering::Data data;
|
||||
const std::array<uint, 1> qt_protobuf_Empty_uint_data;
|
||||
const char qt_protobuf_Empty_char_data[7];
|
||||
} qt_protobuf_Empty_metadata {
|
||||
// data
|
||||
{
|
||||
0, /* = version */
|
||||
0, /* = num fields */
|
||||
1, /* = field number offset */
|
||||
1, /* = property index offset */
|
||||
1, /* = field flags offset */
|
||||
5, /* = message full name length */
|
||||
},
|
||||
// uint_data
|
||||
{
|
||||
// JSON name offsets:
|
||||
6, /* = end-of-string-marker */
|
||||
// Field numbers:
|
||||
// Property indices:
|
||||
// Field flags:
|
||||
},
|
||||
// char_data
|
||||
/* metadata char_data: */
|
||||
"Empty\0" /* = full message name */
|
||||
/* field char_data: */
|
||||
""
|
||||
};
|
||||
|
||||
const QtProtobufPrivate::QProtobufPropertyOrdering Empty::staticPropertyOrdering = {
|
||||
&qt_protobuf_Empty_metadata.data
|
||||
};
|
||||
|
||||
void Empty::registerTypes()
|
||||
{
|
||||
qRegisterMetaType<Empty>();
|
||||
qRegisterMetaType<EmptyRepeated>();
|
||||
}
|
||||
|
||||
Empty::Empty()
|
||||
: QProtobufMessage(&Empty::staticMetaObject, &Empty::staticPropertyOrdering),
|
||||
dptr(new Empty_QtProtobufData)
|
||||
{
|
||||
}
|
||||
|
||||
Empty::Empty(const Empty &other)
|
||||
= default;
|
||||
Empty &Empty::operator =(const Empty &other)
|
||||
{
|
||||
Empty temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
Empty::Empty(Empty &&other) noexcept
|
||||
= default;
|
||||
Empty::operator QVariant() const
|
||||
{
|
||||
return QVariant::fromValue(*this);
|
||||
}
|
||||
bool comparesEqual(const Empty &lhs, const Empty &rhs) noexcept
|
||||
{
|
||||
return operator ==(static_cast<const QProtobufMessage&>(lhs),
|
||||
static_cast<const QProtobufMessage&>(rhs));
|
||||
}
|
||||
|
||||
|
||||
#include "moc_666-invalid-identifier.qpb.cpp"
|
|
@ -0,0 +1,68 @@
|
|||
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
|
||||
|
||||
#ifndef _666_INVALID_IDENTIFIER_QPB_H
|
||||
#define _666_INVALID_IDENTIFIER_QPB_H
|
||||
|
||||
#include "tst_qtgrpcgen_protobuf_invalid-identifier_exports.qpb.h"
|
||||
|
||||
#include <QtProtobuf/qprotobuflazymessagepointer.h>
|
||||
#include <QtProtobuf/qprotobufmessage.h>
|
||||
#include <QtProtobuf/qprotobufobject.h>
|
||||
#include <QtProtobuf/qtprotobuftypes.h>
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
#include <QtCore/qshareddata.h>
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
class Empty;
|
||||
using EmptyRepeated = QList<Empty>;
|
||||
namespace Empty_QtProtobufNested {
|
||||
enum class QtProtobufFieldEnum;
|
||||
} // namespace Empty_QtProtobufNested
|
||||
|
||||
|
||||
class Empty_QtProtobufData;
|
||||
class Empty : public QProtobufMessage
|
||||
{
|
||||
Q_PROTOBUF_OBJECT_EXPORT(QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT)
|
||||
|
||||
public:
|
||||
using QtProtobufFieldEnum = Empty_QtProtobufNested::QtProtobufFieldEnum;
|
||||
QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT Empty();
|
||||
QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT ~Empty();
|
||||
QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT Empty(const Empty &other);
|
||||
QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT Empty &operator =(const Empty &other);
|
||||
QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT Empty(Empty &&other) noexcept;
|
||||
Empty &operator =(Empty &&other) noexcept
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
void swap(Empty &other) noexcept
|
||||
{
|
||||
QProtobufMessage::swap(other);
|
||||
dptr.swap(other.dptr);
|
||||
}
|
||||
QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT Q_IMPLICIT operator QVariant() const;
|
||||
QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT static void registerTypes();
|
||||
|
||||
private:
|
||||
friend QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT bool comparesEqual(const Empty &lhs, const Empty &rhs) noexcept;
|
||||
friend bool operator==(const Empty &lhs, const Empty &rhs) noexcept
|
||||
{
|
||||
return comparesEqual(lhs, rhs);
|
||||
}
|
||||
friend bool operator!=(const Empty &lhs, const Empty &rhs) noexcept
|
||||
{
|
||||
return !comparesEqual(lhs, rhs);
|
||||
}
|
||||
QExplicitlySharedDataPointer<Empty_QtProtobufData> dptr;
|
||||
};
|
||||
namespace Empty_QtProtobufNested {
|
||||
Q_NAMESPACE_EXPORT(QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT)
|
||||
|
||||
} // namespace Empty_QtProtobufNested
|
||||
|
||||
#endif // _666_INVALID_IDENTIFIER_QPB_H
|
|
@ -0,0 +1,31 @@
|
|||
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
|
||||
|
||||
#include "666-invalid-identifier_client.grpc.qpb.h"
|
||||
|
||||
namespace InvalidService {
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
Client::Client(QObject *parent)
|
||||
: QGrpcClientBase("InvalidService"_L1, parent)
|
||||
{
|
||||
}
|
||||
|
||||
Client::~Client() = default;
|
||||
|
||||
std::unique_ptr<QGrpcCallReply> Client::Get(const Empty &arg)
|
||||
{
|
||||
return Get(arg, {});
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<QGrpcCallReply> Client::Get(const Empty &arg, const QGrpcCallOptions &options)
|
||||
{
|
||||
auto reply = call("Get"_L1, arg, options);
|
||||
if (auto *replyPtr = reply.get(); replyPtr != nullptr) {
|
||||
setOperationResponseMetaType(replyPtr, QMetaType::fromType<Empty>());
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
} // namespace InvalidService
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
|
||||
|
||||
#ifndef _666_INVALID_IDENTIFIER_CLIENT_GRPC_QPB_H
|
||||
#define _666_INVALID_IDENTIFIER_CLIENT_GRPC_QPB_H
|
||||
|
||||
#include "666-invalid-identifier.qpb.h"
|
||||
#include "tst_qtgrpcgen_invalid-identifier_exports.qpb.h"
|
||||
|
||||
#include <QtGrpc/qgrpccallreply.h>
|
||||
#include <QtGrpc/qgrpcclientbase.h>
|
||||
#include <QtGrpc/qgrpcstream.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace InvalidService {
|
||||
|
||||
class QPB_TST_QTGRPCGEN_INVALID_IDENTIFIER_EXPORT Client : public QGrpcClientBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Client(QObject *parent = nullptr);
|
||||
~Client() override;
|
||||
|
||||
[[nodiscard]]
|
||||
std::unique_ptr<QGrpcCallReply> Get(const Empty &arg);
|
||||
[[nodiscard]]
|
||||
std::unique_ptr<QGrpcCallReply> Get(const Empty &arg, const QGrpcCallOptions &options);
|
||||
|
||||
|
||||
};
|
||||
} // namespace InvalidService
|
||||
|
||||
#endif // _666_INVALID_IDENTIFIER_CLIENT_GRPC_QPB_H
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
#include "666-invalid-identifier.qpb.h"
|
||||
|
||||
#include <QtProtobuf/qprotobufregistration.h>
|
||||
|
||||
static QtProtobuf::ProtoTypeRegistrar ProtoTypeRegistrarEmpty(qRegisterProtobufType<Empty>);
|
||||
static bool Register_666_invalid_identifierProtobufTypes = [](){ qRegisterProtobufTypes(); return true; }();
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
|
||||
|
||||
#if defined(QT_SHARED) || !defined(QT_STATIC)
|
||||
# if defined(QT_BUILD_TST_QTGRPCGEN_INVALID_IDENTIFIER_LIB)
|
||||
# define QPB_TST_QTGRPCGEN_INVALID_IDENTIFIER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define QPB_TST_QTGRPCGEN_INVALID_IDENTIFIER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define QPB_TST_QTGRPCGEN_INVALID_IDENTIFIER_EXPORT
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
|
||||
|
||||
#if defined(QT_SHARED) || !defined(QT_STATIC)
|
||||
# if defined(QT_BUILD_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_LIB)
|
||||
# define QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define QPB_TST_QTGRPCGEN_PROTOBUF_INVALID_IDENTIFIER_EXPORT
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue