Annotate remaining field semantics.
PiperOrigin-RevId: 509872256
diff --git a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
index 9744204..19bd6b5 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
@@ -51,6 +51,7 @@
namespace compiler {
namespace cpp {
namespace {
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
using Sub = ::google::protobuf::io::Printer::Sub;
std::vector<Sub> Vars(const FieldDescriptor* field, const Options& opts) {
@@ -172,7 +173,8 @@
void SingularEnum::GenerateAccessorDeclarations(io::Printer* p) const {
auto v = p->WithVars(
- AnnotatedAccessors(field_, {"", "set_", "_internal_", "_internal_set_"}));
+ AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
+ auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
p->Emit(R"cc(
$DEPRECATED$ $Enum$ $name$() const;
$DEPRECATED$ void $set_name$($Enum$ value);
@@ -331,9 +333,12 @@
};
void RepeatedEnum::GenerateAccessorDeclarations(io::Printer* p) const {
- auto v = p->WithVars(
- AnnotatedAccessors(field_, {"", "set_", "add_", "mutable_", "_internal_",
- "_internal_add_", "_internal_mutable_"}));
+ auto v = p->WithVars(AnnotatedAccessors(
+ field_, {"", "_internal_", "_internal_add_", "_internal_mutable_"}));
+ auto vs =
+ p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
+ auto vm =
+ p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
p->Emit(R"cc(
public:
diff --git a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
index 79f1015..a91a394 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
@@ -30,6 +30,7 @@
#include <memory>
#include <string>
+#include <tuple>
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
@@ -141,10 +142,12 @@
" ${1$_internal_mutable_$name$$}$();\n"
"public:\n"
"$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
- " ${1$$name$$}$() const;\n"
+ " ${1$$name$$}$() const;\n",
+ descriptor_);
+ format(
"$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
" ${1$mutable_$name$$}$();\n",
- descriptor_);
+ std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::ALIAS));
}
void MapFieldGenerator::GenerateInlineAccessorDefinitions(
diff --git a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
index 6eaadef..b4bf2a9 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
@@ -809,9 +809,11 @@
"$type$* ${1$_internal_add_$name$$}$();\n"
"public:\n",
descriptor_);
+ format("$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n",
+ descriptor_);
+ format("$deprecated_attr$$type$* ${1$add_$name$$}$();\n",
+ std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::SET));
format(
- "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n"
- "$deprecated_attr$$type$* ${1$add_$name$$}$();\n"
"$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
" ${1$$name$$}$() const;\n",
descriptor_);
diff --git a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
index 5bbf298..b15801e 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
@@ -56,7 +56,7 @@
using ::google::protobuf::internal::WireFormat;
using ::google::protobuf::internal::WireFormatLite;
using Sub = ::google::protobuf::io::Printer::Sub;
-using Annotation = ::google::protobuf::GeneratedCodeInfo::Annotation;
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
// For encodings with fixed sizes, returns that size in bytes.
absl::optional<size_t> FixedSize(FieldDescriptor::Type type) {
@@ -193,18 +193,10 @@
};
void SingularPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
+ auto v = p->WithVars(
+ AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
+ auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
p->Emit(
- {
- Sub("name", p->LookupVar("name")).AnnotatedAs(field_),
- Sub("set_name", absl::StrCat("set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_name",
- absl::StrCat("_internal_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_set_name",
- absl::StrCat("_internal_set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- },
R"cc(
$DEPRECATED$ $Type$ $name$() const;
$DEPRECATED$ void $set_name$($Type$ value);
@@ -397,41 +389,27 @@
}
void RepeatedPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
- p->Emit(
- {
- Sub("name", p->LookupVar("name")).AnnotatedAs(field_),
- Sub("set_name", absl::StrCat("set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("add_name", absl::StrCat("add_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("mutable_name", absl::StrCat("mutable_", p->LookupVar("name")))
- .AnnotatedAs(field_),
+ auto v = p->WithVars(AnnotatedAccessors(
+ field_, {"", "_internal_", "_internal_add_", "_internal_mutable_"}));
+ auto vs =
+ p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
+ auto va =
+ p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
+ p->Emit(R"cc(
+ $DEPRECATED$ $Type$ $name$(int index) const;
+ $DEPRECATED$ void $set_name$(int index, $Type$ value);
+ $DEPRECATED$ void $add_name$($Type$ value);
+ $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
+ $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
- Sub("_internal_name",
- absl::StrCat("_internal_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_add_name",
- absl::StrCat("_internal_add_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_mutable_name",
- absl::StrCat("_internal_mutable_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- },
- R"cc(
- $DEPRECATED$ $Type$ $name$(int index) const;
- $DEPRECATED$ void $set_name$(int index, $Type$ value);
- $DEPRECATED$ void $add_name$($Type$ value);
- $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
- $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
+ private:
+ $Type$ $_internal_name$(int index) const;
+ void $_internal_add_name$($Type$ value);
+ const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
+ $pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
- private:
- $Type$ $_internal_name$(int index) const;
- void $_internal_add_name$($Type$ value);
- const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
- $pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
-
- public:
- )cc");
+ public:
+ )cc");
}
void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc
index 88bb015..a9cb054 100644
--- a/src/google/protobuf/compiler/cpp/message.cc
+++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -85,6 +85,7 @@
using ::google::protobuf::internal::WireFormatLite;
using ::google::protobuf::internal::cpp::HasHasbit;
using ::google::protobuf::internal::cpp::Utf8CheckMode;
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
using Sub = ::google::protobuf::io::Printer::Sub;
static constexpr int kNoHasbit = -1;
@@ -730,7 +731,10 @@
{"clearer",
[&] {
p->Emit({Sub("clear_name", absl::StrCat("clear_", name))
- .AnnotatedAs(field)},
+ .AnnotatedAs({
+ field,
+ Semantic::kSet,
+ })},
R"cc(
$deprecated_attr $void $clear_name$() $impl$;
)cc");
diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
index feb5a7f..e95ee56 100644
--- a/src/google/protobuf/compiler/cpp/metadata_test.cc
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -177,6 +177,270 @@
EXPECT_FALSE(atu::GetAnnotationSubstring(test, annotation).has_value());
}
+constexpr absl::string_view kEnumFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ enum Enum { VALUE = 0; }
+ message Message {
+ optional Enum efield = 1;
+ repeated Enum refield = 2;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesEnumSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kEnumFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "efield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_efield" || *substring == "clear_efield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_refield" || *substring == "clear_refield" ||
+ *substring == "add_refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kMapFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ map<string, int32> mfield = 1;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesMapSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kMapFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kPrimFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional int32 ifield = 1;
+ repeated int32 rifield = 2;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesPrimSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kPrimFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "ifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_ifield" || *substring == "clear_ifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rifield" || *substring == "clear_rifield" ||
+ *substring == "add_rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kCordFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional string sfield = 1 [ctype = CORD];
+ repeated string rsfield = 2 [ctype = CORD];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesCordSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kCordFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_sfield" || *substring == "clear_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rsfield" || *substring == "clear_rsfield" ||
+ *substring == "add_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kStringPieceFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional string sfield = 1 [ctype = STRING_PIECE];
+ repeated string rsfield = 2 [ctype = STRING_PIECE];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesStringPieceSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kStringPieceFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_sfield" || *substring == "set_alias_sfield" ||
+ *substring == "clear_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rsfield" ||
+ *substring == "set_alias_rsfield" ||
+ *substring == "clear_rsfield" ||
+ *substring == "add_alias_rsfield" ||
+ *substring == "add_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
constexpr absl::string_view kStringFieldTestFile = R"(
syntax = "proto2";
package foo;
@@ -205,7 +469,7 @@
if (*substring == "sfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (*substring == "set_sfield") {
+ } else if (*substring == "set_sfield" || *substring == "clear_sfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
annotation->semantic());
} else if (*substring == "mutable_sfield") {
@@ -223,7 +487,8 @@
if (*substring == "rsfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (*substring == "set_rsfield") {
+ } else if (*substring == "set_rsfield" || *substring == "clear_rsfield" ||
+ *substring == "add_rsfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
annotation->semantic());
} else if (*substring == "mutable_rsfield") {
@@ -265,6 +530,9 @@
if (*substring == "mfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
+ } else if (*substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
} else if (*substring == "mutable_mfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
annotation->semantic());
@@ -277,15 +545,60 @@
for (const auto* annotation : annotations) {
auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
ASSERT_TRUE(substring.has_value());
- if (substring == "rmfield") {
+ if (*substring == "rmfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (substring == "mutable_rmfield") {
+ } else if (*substring == "add_rmfield" || *substring == "clear_rmfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rmfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
annotation->semantic());
}
}
}
+
+constexpr absl::string_view kLazyMessageFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message SMessage { }
+ message Message {
+ optional SMessage mfield = 1 [lazy=true];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesLazyMessageSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kLazyMessageFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(1).name());
+ std::vector<int> field_path;
+ field_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+ field_path.push_back(1);
+ field_path.push_back(DescriptorProto::kFieldFieldNumber);
+ field_path.push_back(0);
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "mutable_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ } else if (*substring == "set_encoded_mfield" ||
+ *substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+}
} // namespace
} // namespace cpp
} // namespace compiler