hpb: escape NULL enum values and types to NULL_

This change ensures that enums and enum values named NULL are correctly escaped to NULL_ in the generated C++ code,
avoiding conflicts with the NULL macro. Added a regression test case to verify the fix.

PiperOrigin-RevId: 861526129
This commit is contained in:
Protobuf Team Bot 2026-01-26 22:41:53 -08:00 committed by Copybara-Service
parent 16e81513e6
commit a4dd212110
6 changed files with 53 additions and 8 deletions

View file

@ -19,6 +19,7 @@
#include "absl/strings/string_view.h"
#include "hpb_generator/context.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/keywords.h"
#include "hpb_generator/names.h"
#include "google/protobuf/descriptor.h"
@ -66,7 +67,7 @@ std::string EnumTypeName(const google::protobuf::EnumDescriptor* enum_descriptor
return absl::StrCat(kNoPackageNamePrefix,
ToCIdent(enum_descriptor->name()));
}
return ToCIdent(enum_descriptor->name());
return ResolveKeywordConflict(ToCIdent(enum_descriptor->name()));
} else {
// Since the enum is in global name space (no package), it will have the
// same classified name as the C header include, to prevent collision
@ -94,7 +95,7 @@ std::string EnumValueSymbolInNameSpace(
if (desc->file()->package().empty()) {
return absl::StrCat(kNoPackageNamePrefix, ToCIdent(value->name()));
}
return ToCIdent(value->name());
return ResolveKeywordConflict(ToCIdent(value->name()));
}
}

View file

@ -13,6 +13,7 @@
#include "absl/strings/str_cat.h"
#include "hpb_generator/context.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/keywords.h"
#include "hpb_generator/names.h"
#include "google/protobuf/descriptor.h"
#include "upb_generator/c/names.h"
@ -54,7 +55,7 @@ void WriteExtensionIdentifierHeader(const google::protobuf::FieldDescriptor* ext
{"linkage", linkage},
{"mini_table_name",
absl::StrCat(ExtensionIdentifierBase(ext), "_", ext->name(), "_ext")},
{"extension_name", ext->name()},
{"extension_name", ResolveKeywordConflict(ext->name())},
{"extension_number", ext->number()}},
R"cc(
inline $linkage$ constexpr ::hpb::internal::ExtensionIdentifier<

View file

@ -21,6 +21,7 @@
#include "hpb_generator/gen_enums.h"
#include "hpb_generator/gen_extensions.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/keywords.h"
#include "hpb_generator/names.h"
#include "google/protobuf/descriptor.h"
#include "upb_generator/c/names.h"
@ -516,21 +517,24 @@ void WriteUsingEnumsInHeader(
message->full_name()) {
continue;
}
ctx.Emit({{"enum_name", enum_descriptor->name()}}, "using $enum_name$");
ctx.Emit({{"enum_name", ResolveKeywordConflict(enum_descriptor->name())}},
"using $enum_name$");
if (enum_descriptor->options().deprecated()) {
ctx.Emit({{"enum_name", enum_descriptor->name()}},
ctx.Emit({{"enum_name", ResolveKeywordConflict(enum_descriptor->name())}},
" ABSL_DEPRECATED(\"Proto enum $enum_name$\")");
}
ctx.Emit({{"enum_resolved_type_name", enum_resolved_type_name}},
" = $enum_resolved_type_name$;\n");
int value_count = enum_descriptor->value_count();
for (int i = 0; i < value_count; i++) {
ctx.Emit({{"enum_name", enum_descriptor->name()},
{"enum_value_name", enum_descriptor->value(i)->name()}},
ctx.Emit({{"enum_name", ResolveKeywordConflict(enum_descriptor->name())},
{"enum_value_name",
ResolveKeywordConflict(enum_descriptor->value(i)->name())}},
"static constexpr $enum_name$ $enum_value_name$");
if (enum_descriptor->options().deprecated() ||
enum_descriptor->value(i)->options().deprecated()) {
ctx.Emit({{"enum_value_name", enum_descriptor->value(i)->name()}},
ctx.Emit({{"enum_value_name",
ResolveKeywordConflict(enum_descriptor->value(i)->name())}},
" ABSL_DEPRECATED(\"Proto enum value $enum_value_name$\") ");
}
ctx.Emit({{"enum_value_symbol",

View file

@ -52,6 +52,13 @@ proto_library(
],
)
proto_library(
name = "null_enum_proto",
srcs = [
"null_enum.proto",
],
)
proto_library(
name = "no_package_enum_user_proto",
srcs = [
@ -90,6 +97,12 @@ hpb_proto_library(
deps = [":naming_conflict_proto"],
)
hpb_proto_library(
name = "null_enum_hpb_proto",
visibility = ["//visibility:private"],
deps = [":null_enum_proto"],
)
hpb_proto_library(
name = "no_package_hpb_proto",
deps = [
@ -167,6 +180,7 @@ cc_test(
":test_model_hpb_proto",
":test_model_upb_proto",
":naming_conflict_hpb_proto",
":null_enum_hpb_proto",
"@googletest//:gtest",
"@googletest//:gtest_main",
"@abseil-cpp//absl/status:statusor",

View file

@ -0,0 +1,22 @@
syntax = "proto3";
package hpb_test;
enum TestEnumWithNull {
TYPE_UNSPECIFIED = 0;
NULL = 1;
}
message MessageWithEnum {
enum NestedEnum {
NESTED_TYPE_UNSPECIFIED = 0;
NULL = 1;
}
}
message MessageWithNullEnum {
enum NULL {
UNSPECIFIED = 0;
VALUE = 1;
}
}

View file

@ -14,6 +14,7 @@
#include "absl/strings/string_view.h"
#include "hpb_generator/tests/child_model.hpb.h"
#include "hpb_generator/tests/no_package.hpb.h"
#include "hpb_generator/tests/null_enum.hpb.h"
#include "hpb_generator/tests/set_alias.hpb.h"
#include "hpb_generator/tests/test_enum.hpb.h"
#include "hpb_generator/tests/test_extension.hpb.h"
@ -50,6 +51,8 @@ TEST(CppGeneratedCode, ImportedEnum) { EXPECT_EQ(3, TestEnum::DEVICE_MONITOR); }
TEST(CppGeneratedCode, Enum) { EXPECT_EQ(1, RED); }
TEST(CppGeneratedCode, NullEnum) { EXPECT_EQ(1, hpb_test::protos::NULL_); }
TEST(CppGeneratedCode, EnumNoPackage) { EXPECT_EQ(1, ::hpb_CELSIUS); }
TEST(CppGeneratedCode, EnumContainingMessage) {