Add inner verification code to detect accessors missing required annotations.

This change has no behavior change, other than CHECK-fail `protoc` when a bug is detected instead of generating the buggy code.

PiperOrigin-RevId: 595467581
pull/15247/head
Protobuf Team Bot 11 months ago committed by Copybara-Service
parent 807f00b4db
commit 3869318558
  1. 2
      src/google/protobuf/compiler/cpp/field.cc
  2. 24
      src/google/protobuf/compiler/cpp/field_generators/cord_field.cc
  3. 32
      src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
  4. 8
      src/google/protobuf/compiler/cpp/field_generators/map_field.cc
  5. 49
      src/google/protobuf/compiler/cpp/field_generators/message_field.cc
  6. 34
      src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
  7. 62
      src/google/protobuf/compiler/cpp/field_generators/string_field.cc
  8. 70
      src/google/protobuf/compiler/cpp/message.cc
  9. 7
      src/google/protobuf/compiler/plugin.pb.h
  10. 51
      src/google/protobuf/descriptor.pb.h
  11. 3
      src/google/protobuf/io/printer.cc
  12. 22
      src/google/protobuf/io/printer.h
  13. 29
      src/google/protobuf/io/printer_unittest.cc

@ -43,6 +43,8 @@ std::vector<Sub> FieldVars(const FieldDescriptor* field, const Options& opts) {
// This will eventually be renamed to "field", once the existing "field" // This will eventually be renamed to "field", once the existing "field"
// variable is replaced with "field_" everywhere. // variable is replaced with "field_" everywhere.
{"name", FieldName(field)}, {"name", FieldName(field)},
// Same as above, but represents internal use.
{"name_internal", FieldName(field)},
{"index", field->index()}, {"index", field->index()},
{"number", field->number()}, {"number", field->number()},

@ -174,7 +174,7 @@ void CordFieldGenerator::GenerateInlineAccessorDefinitions(
io::Printer* printer) const { io::Printer* printer) const {
auto v = printer->WithVars(variables_); auto v = printer->WithVars(variables_);
printer->Emit(R"cc( printer->Emit(R"cc(
inline const ::absl::Cord& $classname$::_internal_$name$() const { inline const ::absl::Cord& $classname$::_internal_$name_internal$() const {
return $field$; return $field$;
} }
)cc"); )cc");
@ -183,18 +183,20 @@ void CordFieldGenerator::GenerateInlineAccessorDefinitions(
ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$full_name$) // @@protoc_insertion_point(field_get:$full_name$)
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
printer->Emit(R"cc( printer->Emit(R"cc(
inline void $classname$::_internal_set_$name$(const ::absl::Cord& value) { inline void $classname$::_internal_set_$name_internal$(
const ::absl::Cord& value) {
$set_hasbit$; $set_hasbit$;
$field$ = value; $field$ = value;
} }
)cc"); )cc");
printer->Emit(R"cc( printer->Emit(R"cc(
inline void $classname$::set_$name$(const ::absl::Cord& value) { inline void $classname$::set_$name$(const ::absl::Cord& value) {
$PrepareSplitMessageForWrite$ _internal_set_$name$(value); $PrepareSplitMessageForWrite$;
_internal_set_$name_internal$(value);
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set:$full_name$) // @@protoc_insertion_point(field_set:$full_name$)
} }
@ -209,7 +211,7 @@ void CordFieldGenerator::GenerateInlineAccessorDefinitions(
} }
)cc"); )cc");
printer->Emit(R"cc( printer->Emit(R"cc(
inline ::absl::Cord* $classname$::_internal_mutable_$name$() { inline ::absl::Cord* $classname$::_internal_mutable_$name_internal$() {
$set_hasbit$; $set_hasbit$;
return &$field$; return &$field$;
} }
@ -333,7 +335,7 @@ void CordOneofFieldGenerator::GenerateInlineAccessorDefinitions(
io::Printer* printer) const { io::Printer* printer) const {
auto v = printer->WithVars(variables_); auto v = printer->WithVars(variables_);
printer->Emit(R"cc( printer->Emit(R"cc(
inline const ::absl::Cord& $classname$::_internal_$name$() const { inline const ::absl::Cord& $classname$::_internal_$name_internal$() const {
if ($has_field$) { if ($has_field$) {
return *$field$; return *$field$;
} }
@ -345,14 +347,14 @@ void CordOneofFieldGenerator::GenerateInlineAccessorDefinitions(
ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$full_name$) // @@protoc_insertion_point(field_get:$full_name$)
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
printer->Emit(R"cc( printer->Emit(R"cc(
inline void $classname$::set_$name$(const ::absl::Cord& value) { inline void $classname$::set_$name$(const ::absl::Cord& value) {
if ($not_has_field$) { if ($not_has_field$) {
clear_$oneof_name$(); clear_$oneof_name$();
set_has_$name$(); set_has_$name_internal$();
$field$ = new ::absl::Cord; $field$ = new ::absl::Cord;
::$proto_ns$::Arena* arena = GetArena(); ::$proto_ns$::Arena* arena = GetArena();
if (arena != nullptr) { if (arena != nullptr) {
@ -368,7 +370,7 @@ void CordOneofFieldGenerator::GenerateInlineAccessorDefinitions(
inline void $classname$::set_$name$(::absl::string_view value) { inline void $classname$::set_$name$(::absl::string_view value) {
if ($not_has_field$) { if ($not_has_field$) {
clear_$oneof_name$(); clear_$oneof_name$();
set_has_$name$(); set_has_$name_internal$();
$field$ = new ::absl::Cord; $field$ = new ::absl::Cord;
::$proto_ns$::Arena* arena = GetArena(); ::$proto_ns$::Arena* arena = GetArena();
if (arena != nullptr) { if (arena != nullptr) {
@ -381,10 +383,10 @@ void CordOneofFieldGenerator::GenerateInlineAccessorDefinitions(
} }
)cc"); )cc");
printer->Emit(R"cc( printer->Emit(R"cc(
inline ::absl::Cord* $classname$::_internal_mutable_$name$() { inline ::absl::Cord* $classname$::_internal_mutable_$name_internal$() {
if ($not_has_field$) { if ($not_has_field$) {
clear_$oneof_name$(); clear_$oneof_name$();
set_has_$name$(); set_has_$name_internal$();
$field$ = new ::absl::Cord; $field$ = new ::absl::Cord;
::$proto_ns$::Arena* arena = GetArena(); ::$proto_ns$::Arena* arena = GetArena();
if (arena != nullptr) { if (arena != nullptr) {

@ -167,7 +167,7 @@ void SingularEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
inline $Enum$ $Msg$::$name$() const { inline $Enum$ $Msg$::$name$() const {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
@ -178,13 +178,13 @@ void SingularEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
$assert_valid$; $assert_valid$;
if ($not_has_field$) { if ($not_has_field$) {
clear_$oneof_name$(); clear_$oneof_name$();
set_has_$name$(); set_has_$name_internal$();
} }
$field_$ = value; $field_$ = value;
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set:$pkg.Msg.field$) // @@protoc_insertion_point(field_set:$pkg.Msg.field$)
} }
inline $Enum$ $Msg$::_internal_$name$() const { inline $Enum$ $Msg$::_internal_$name_internal$() const {
if ($has_field$) { if ($has_field$) {
return static_cast<$Enum$>($field_$); return static_cast<$Enum$>($field_$);
} }
@ -195,16 +195,16 @@ void SingularEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
p->Emit(R"cc( p->Emit(R"cc(
inline void $Msg$::set_$name$($Enum$ value) { inline void $Msg$::set_$name$($Enum$ value) {
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
_internal_set_$name$(value); _internal_set_$name_internal$(value);
$set_hasbit$; $set_hasbit$;
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set:$pkg.Msg.field$) // @@protoc_insertion_point(field_set:$pkg.Msg.field$)
} }
inline $Enum$ $Msg$::_internal_$name$() const { inline $Enum$ $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return static_cast<$Enum$>($field_$); return static_cast<$Enum$>($field_$);
} }
inline void $Msg$::_internal_set_$name$($Enum$ value) { inline void $Msg$::_internal_set_$name_internal$($Enum$ value) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
$assert_valid$; $assert_valid$;
$field_$ = value; $field_$ = value;
@ -400,13 +400,13 @@ void RepeatedEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
inline $Enum$ $Msg$::$name$(int index) const { inline $Enum$ $Msg$::$name$(int index) const {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
return static_cast<$Enum$>(_internal_$name$().Get(index)); return static_cast<$Enum$>(_internal_$name_internal$().Get(index));
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
inline void $Msg$::set_$name$(int index, $Enum$ value) { inline void $Msg$::set_$name$(int index, $Enum$ value) {
$assert_valid$; $assert_valid$;
_internal_mutable_$name$()->Set(index, value); _internal_mutable_$name_internal$()->Set(index, value);
$annotate_set$ $annotate_set$
// @@protoc_insertion_point(field_set:$pkg.Msg.field$) // @@protoc_insertion_point(field_set:$pkg.Msg.field$)
} }
@ -415,7 +415,7 @@ void RepeatedEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
inline void $Msg$::add_$name$($Enum$ value) { inline void $Msg$::add_$name$($Enum$ value) {
$assert_valid$; $assert_valid$;
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
_internal_mutable_$name$()->Add(value); _internal_mutable_$name_internal$()->Add(value);
$annotate_add$ $annotate_add$
// @@protoc_insertion_point(field_add:$pkg.Msg.field$) // @@protoc_insertion_point(field_add:$pkg.Msg.field$)
} }
@ -425,7 +425,7 @@ void RepeatedEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_list$; $annotate_list$;
// @@protoc_insertion_point(field_list:$pkg.Msg.field$) // @@protoc_insertion_point(field_list:$pkg.Msg.field$)
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
@ -434,16 +434,17 @@ void RepeatedEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
$annotate_mutable_list$; $annotate_mutable_list$;
// @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$)
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
return _internal_mutable_$name$(); return _internal_mutable_$name_internal$();
} }
)cc"); )cc");
if (should_split()) { if (should_split()) {
p->Emit(R"cc( p->Emit(R"cc(
inline const $pb$::RepeatedField<int>& $Msg$::_internal_$name$() const { inline const $pb$::RepeatedField<int>& $Msg$::_internal_$name_internal$()
const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return *$field_$; return *$field_$;
} }
inline $pb$::RepeatedField<int>* $Msg$::_internal_mutable_$name$() { inline $pb$::RepeatedField<int>* $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
if ($field_$.IsDefault()) { if ($field_$.IsDefault()) {
@ -455,11 +456,12 @@ void RepeatedEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
)cc"); )cc");
} else { } else {
p->Emit(R"cc( p->Emit(R"cc(
inline const $pb$::RepeatedField<int>& $Msg$::_internal_$name$() const { inline const $pb$::RepeatedField<int>& $Msg$::_internal_$name_internal$()
const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return $field_$; return $field_$;
} }
inline $pb$::RepeatedField<int>* $Msg$::_internal_mutable_$name$() { inline $pb$::RepeatedField<int>* $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return &$field_$; return &$field_$;
} }

@ -215,7 +215,7 @@ void Map::GenerateAccessorDeclarations(io::Printer* p) const {
void Map::GenerateInlineAccessorDefinitions(io::Printer* p) const { void Map::GenerateInlineAccessorDefinitions(io::Printer* p) const {
p->Emit(R"cc( p->Emit(R"cc(
inline const $Map$& $Msg$::_internal_$name$() const { inline const $Map$& $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return $field_$.GetMap(); return $field_$.GetMap();
} }
@ -224,11 +224,11 @@ void Map::GenerateInlineAccessorDefinitions(io::Printer* p) const {
inline const $Map$& $Msg$::$name$() const ABSL_ATTRIBUTE_LIFETIME_BOUND { inline const $Map$& $Msg$::$name$() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_map:$pkg.Msg.field$) // @@protoc_insertion_point(field_map:$pkg.Msg.field$)
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
inline $Map$* $Msg$::_internal_mutable_$name$() { inline $Map$* $Msg$::_internal_mutable_$name_internal$() {
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
return $field_$.MutableMap(); return $field_$.MutableMap();
@ -238,7 +238,7 @@ void Map::GenerateInlineAccessorDefinitions(io::Printer* p) const {
inline $Map$* $Msg$::mutable_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND { inline $Map$* $Msg$::mutable_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_mutable$; $annotate_mutable$;
// @@protoc_insertion_point(field_mutable_map:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable_map:$pkg.Msg.field$)
return _internal_mutable_$name$(); return _internal_mutable_$name_internal$();
} }
)cc"); )cc");
} }

@ -198,7 +198,7 @@ void SingularMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
}}, }},
}, },
R"cc( R"cc(
inline const $Submsg$& $Msg$::_internal_$name$() const { inline const $Submsg$& $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
$StrongRef$; $StrongRef$;
const $Submsg$* p = $cast_field_$; const $Submsg$* p = $cast_field_$;
@ -207,7 +207,7 @@ void SingularMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
inline const $Submsg$& $Msg$::$name$() const ABSL_ATTRIBUTE_LIFETIME_BOUND { inline const $Submsg$& $Msg$::$name$() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
return _internal_$name$(); return _internal_$name_internal$();
} }
inline void $Msg$::unsafe_arena_set_allocated_$name$($Submsg$* value) { inline void $Msg$::unsafe_arena_set_allocated_$name$($Submsg$* value) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
@ -256,7 +256,7 @@ void SingularMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
$field_$ = nullptr; $field_$ = nullptr;
return temp; return temp;
} }
inline $Submsg$* $Msg$::_internal_mutable_$name$() { inline $Submsg$* $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
$StrongRef$; $StrongRef$;
if ($field_$ == nullptr) { if ($field_$ == nullptr) {
@ -270,7 +270,7 @@ void SingularMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
//~ able to prepare split message allocation. //~ able to prepare split message allocation.
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
$set_hasbit$; $set_hasbit$;
$Submsg$* _msg = _internal_mutable_$name$(); $Submsg$* _msg = _internal_mutable_$name_internal$();
$annotate_mutable$; $annotate_mutable$;
// @@protoc_insertion_point(field_mutable:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable:$pkg.Msg.field$)
return _msg; return _msg;
@ -539,7 +539,7 @@ void OneofMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
inline const $Submsg$& $Msg$::_internal_$name$() const { inline const $Submsg$& $Msg$::_internal_$name_internal$() const {
$StrongRef$; $StrongRef$;
return $has_field$ ? *$cast_field_$ : reinterpret_cast<$Submsg$&>($kDefault$); return $has_field$ ? *$cast_field_$ : reinterpret_cast<$Submsg$&>($kDefault$);
} }
@ -548,7 +548,7 @@ void OneofMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
inline const $Submsg$& $Msg$::$name$() const ABSL_ATTRIBUTE_LIFETIME_BOUND { inline const $Submsg$& $Msg$::$name$() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
@ -573,7 +573,7 @@ void OneofMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
// set the new value. // set the new value.
clear_$oneof_name$(); clear_$oneof_name$();
if (value) { if (value) {
set_has_$name$(); set_has_$name_internal$();
$field_$ = $weak_cast$(value); $field_$ = $weak_cast$(value);
} }
$annotate_set$; $annotate_set$;
@ -581,11 +581,11 @@ void OneofMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
inline $Submsg$* $Msg$::_internal_mutable_$name$() { inline $Submsg$* $Msg$::_internal_mutable_$name_internal$() {
$StrongRef$; $StrongRef$;
if ($not_has_field$) { if ($not_has_field$) {
clear_$oneof_name$(); clear_$oneof_name$();
set_has_$name$(); set_has_$name_internal$();
$field_$ = $field_$ =
$weak_cast$($superclass$::DefaultConstruct<$Submsg$>(GetArena())); $weak_cast$($superclass$::DefaultConstruct<$Submsg$>(GetArena()));
} }
@ -594,7 +594,7 @@ void OneofMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
inline $Submsg$* $Msg$::mutable_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND { inline $Submsg$* $Msg$::mutable_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND {
$Submsg$* _msg = _internal_mutable_$name$(); $Submsg$* _msg = _internal_mutable_$name_internal$();
$annotate_mutable$; $annotate_mutable$;
// @@protoc_insertion_point(field_mutable:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable:$pkg.Msg.field$)
return _msg; return _msg;
@ -745,7 +745,7 @@ void RepeatedMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
$annotate_mutable$; $annotate_mutable$;
// @@protoc_insertion_point(field_mutable:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable:$pkg.Msg.field$)
$StrongRef$; $StrongRef$;
return _internal_mutable_$name$()->Mutable(index); return _internal_mutable_$name_internal$()->Mutable(index);
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
@ -755,7 +755,7 @@ void RepeatedMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
// @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$)
$StrongRef$; $StrongRef$;
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
return _internal_mutable_$name$(); return _internal_mutable_$name_internal$();
} }
)cc"); )cc");
p->Emit( p->Emit(
@ -774,13 +774,13 @@ void RepeatedMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
$StrongRef$; $StrongRef$;
return _internal_$name$().$Get$(index$GetExtraArg$); return _internal_$name_internal$().$Get$(index$GetExtraArg$);
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
inline $Submsg$* $Msg$::add_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND { inline $Submsg$* $Msg$::add_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
$Submsg$* _add = _internal_mutable_$name$()->Add(); $Submsg$* _add = _internal_mutable_$name_internal$()->Add();
$annotate_add_mutable$; $annotate_add_mutable$;
// @@protoc_insertion_point(field_add:$pkg.Msg.field$) // @@protoc_insertion_point(field_add:$pkg.Msg.field$)
return _add; return _add;
@ -792,19 +792,19 @@ void RepeatedMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
$annotate_list$; $annotate_list$;
// @@protoc_insertion_point(field_list:$pkg.Msg.field$) // @@protoc_insertion_point(field_list:$pkg.Msg.field$)
$StrongRef$; $StrongRef$;
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
if (should_split()) { if (should_split()) {
p->Emit(R"cc( p->Emit(R"cc(
inline const $pb$::$Weak$RepeatedPtrField<$Submsg$>& inline const $pb$::$Weak$RepeatedPtrField<$Submsg$>&
$Msg$::_internal$_weak$_$name$() const { $Msg$::_internal$_weak$_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return *$field_$; return *$field_$;
} }
inline $pb$::$Weak$RepeatedPtrField<$Submsg$>* inline $pb$::$Weak$RepeatedPtrField<$Submsg$>*
$Msg$::_internal_mutable$_weak$_$name$() { $Msg$::_internal_mutable$_weak$_$name_internal$() {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
if ($field_$.IsDefault()) { if ($field_$.IsDefault()) {
@ -817,12 +817,12 @@ void RepeatedMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
} else { } else {
p->Emit(R"cc( p->Emit(R"cc(
inline const $pb$::$Weak$RepeatedPtrField<$Submsg$>& inline const $pb$::$Weak$RepeatedPtrField<$Submsg$>&
$Msg$::_internal$_weak$_$name$() const { $Msg$::_internal$_weak$_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return $field_$; return $field_$;
} }
inline $pb$::$Weak$RepeatedPtrField<$Submsg$>* inline $pb$::$Weak$RepeatedPtrField<$Submsg$>*
$Msg$::_internal_mutable$_weak$_$name$() { $Msg$::_internal_mutable$_weak$_$name_internal$() {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return &$field_$; return &$field_$;
} }
@ -830,12 +830,13 @@ void RepeatedMessage::GenerateInlineAccessorDefinitions(io::Printer* p) const {
} }
if (is_weak()) { if (is_weak()) {
p->Emit(R"cc( p->Emit(R"cc(
inline const $pb$::RepeatedPtrField<$Submsg$>& $Msg$::_internal_$name$() inline const $pb$::RepeatedPtrField<$Submsg$>&
const { $Msg$::_internal_$name_internal$() const {
return _internal_weak_$name$().weak; return _internal_weak_$name_internal$().weak;
} }
inline $pb$::RepeatedPtrField<$Submsg$>* $Msg$::_internal_mutable_$name$() { inline $pb$::RepeatedPtrField<$Submsg$>*
return &_internal_mutable_weak_$name$()->weak; $Msg$::_internal_mutable_$name_internal$() {
return &_internal_mutable_weak_$name_internal$()->weak;
} }
)cc"); )cc");
} }

@ -190,7 +190,7 @@ void SingularPrimitive::GenerateInlineAccessorDefinitions(
inline $Type$ $Msg$::$name$() const { inline $Type$ $Msg$::$name$() const {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
@ -200,13 +200,13 @@ void SingularPrimitive::GenerateInlineAccessorDefinitions(
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
if ($not_has_field$) { if ($not_has_field$) {
clear_$oneof_name$(); clear_$oneof_name$();
set_has_$name$(); set_has_$name_internal$();
} }
$field_$ = value; $field_$ = value;
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set:$pkg.Msg.field$) // @@protoc_insertion_point(field_set:$pkg.Msg.field$)
} }
inline $Type$ $Msg$::_internal_$name$() const { inline $Type$ $Msg$::_internal_$name_internal$() const {
if ($has_field$) { if ($has_field$) {
return $field_$; return $field_$;
} }
@ -217,16 +217,16 @@ void SingularPrimitive::GenerateInlineAccessorDefinitions(
p->Emit(R"cc( p->Emit(R"cc(
inline void $Msg$::set_$name$($Type$ value) { inline void $Msg$::set_$name$($Type$ value) {
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
_internal_set_$name$(value); _internal_set_$name_internal$(value);
$set_hasbit$; $set_hasbit$;
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set:$pkg.Msg.field$) // @@protoc_insertion_point(field_set:$pkg.Msg.field$)
} }
inline $Type$ $Msg$::_internal_$name$() const { inline $Type$ $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return $field_$; return $field_$;
} }
inline void $Msg$::_internal_set_$name$($Type$ value) { inline void $Msg$::_internal_set_$name_internal$($Type$ value) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
$field_$ = value; $field_$ = value;
} }
@ -469,20 +469,20 @@ void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
inline $Type$ $Msg$::$name$(int index) const { inline $Type$ $Msg$::$name$(int index) const {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
return _internal_$name$().Get(index); return _internal_$name_internal$().Get(index);
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
inline void $Msg$::set_$name$(int index, $Type$ value) { inline void $Msg$::set_$name$(int index, $Type$ value) {
$annotate_set$; $annotate_set$;
_internal_mutable_$name$()->Set(index, value); _internal_mutable_$name_internal$()->Set(index, value);
// @@protoc_insertion_point(field_set:$pkg.Msg.field$) // @@protoc_insertion_point(field_set:$pkg.Msg.field$)
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
inline void $Msg$::add_$name$($Type$ value) { inline void $Msg$::add_$name$($Type$ value) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
_internal_mutable_$name$()->Add(value); _internal_mutable_$name_internal$()->Add(value);
$annotate_add$; $annotate_add$;
// @@protoc_insertion_point(field_add:$pkg.Msg.field$) // @@protoc_insertion_point(field_add:$pkg.Msg.field$)
} }
@ -492,7 +492,7 @@ void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_list$; $annotate_list$;
// @@protoc_insertion_point(field_list:$pkg.Msg.field$) // @@protoc_insertion_point(field_list:$pkg.Msg.field$)
return _internal_$name$(); return _internal_$name_internal$();
} }
)cc"); )cc");
p->Emit(R"cc( p->Emit(R"cc(
@ -501,18 +501,18 @@ void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
$annotate_mutable_list$; $annotate_mutable_list$;
// @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$)
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
return _internal_mutable_$name$(); return _internal_mutable_$name_internal$();
} }
)cc"); )cc");
if (should_split()) { if (should_split()) {
p->Emit(R"cc( p->Emit(R"cc(
inline const $pb$::RepeatedField<$Type$>& $Msg$::_internal_$name$() inline const $pb$::RepeatedField<$Type$>&
const { $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return *$field_$; return *$field_$;
} }
inline $pb$::RepeatedField<$Type$>* $Msg$::_internal_mutable_$name$() { inline $pb$::RepeatedField<$Type$>* $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
if ($field_$.IsDefault()) { if ($field_$.IsDefault()) {
@ -524,12 +524,12 @@ void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
)cc"); )cc");
} else { } else {
p->Emit(R"cc( p->Emit(R"cc(
inline const $pb$::RepeatedField<$Type$>& $Msg$::_internal_$name$() inline const $pb$::RepeatedField<$Type$>&
const { $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return $field_$; return $field_$;
} }
inline $pb$::RepeatedField<$Type$>* $Msg$::_internal_mutable_$name$() { inline $pb$::RepeatedField<$Type$>* $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return &$field_$; return &$field_$;
} }

@ -300,7 +300,7 @@ void UpdateHasbitSet(io::Printer* p, bool is_oneof) {
if ($not_has_field$) { if ($not_has_field$) {
clear_$oneof_name$(); clear_$oneof_name$();
set_has_$name$(); set_has_$name_internal$();
$field_$.InitDefault(); $field_$.InitDefault();
} }
)cc"); )cc");
@ -312,7 +312,7 @@ void ArgsForSetter(io::Printer* p, bool inlined) {
return; return;
} }
p->Emit( p->Emit(
"GetArena(), _internal_$name$_donated(), " "GetArena(), _internal_$name_internal$_donated(), "
"&$donating_states_word$, $mask_for_undonate$, this"); "&$donating_states_word$, $mask_for_undonate$, this");
} }
@ -342,7 +342,7 @@ void SingularString::ReleaseImpl(io::Printer* p) const {
} }
$clear_hasbit$; $clear_hasbit$;
return $field_$.Release(GetArena(), _internal_$name$_donated()); return $field_$.Release(GetArena(), _internal_$name_internal$_donated());
)cc"); )cc");
return; return;
} }
@ -377,7 +377,7 @@ void SingularString::SetAllocatedImpl(io::Printer* p) const {
clear_$oneof_name$(); clear_$oneof_name$();
} }
if (value != nullptr) { if (value != nullptr) {
set_has_$name$(); set_has_$name_internal$();
$field_$.InitAllocated(value, GetArena()); $field_$.InitAllocated(value, GetArena());
} }
)cc"); )cc");
@ -451,7 +451,7 @@ void SingularString::GenerateInlineAccessorDefinitions(io::Printer* p) const {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
$if_IsDefault$; $if_IsDefault$;
return _internal_$name$(); return _internal_$name_internal$();
} }
template <typename Arg_, typename... Args_> template <typename Arg_, typename... Args_>
inline PROTOBUF_ALWAYS_INLINE void $Msg$::set_$name$(Arg_&& arg, inline PROTOBUF_ALWAYS_INLINE void $Msg$::set_$name$(Arg_&& arg,
@ -465,24 +465,24 @@ void SingularString::GenerateInlineAccessorDefinitions(io::Printer* p) const {
} }
inline std::string* $Msg$::mutable_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND { inline std::string* $Msg$::mutable_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND {
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
std::string* _s = _internal_mutable_$name$(); std::string* _s = _internal_mutable_$name_internal$();
$annotate_mutable$; $annotate_mutable$;
// @@protoc_insertion_point(field_mutable:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable:$pkg.Msg.field$)
return _s; return _s;
} }
inline const std::string& $Msg$::_internal_$name$() const { inline const std::string& $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
$check_hasbit$; $check_hasbit$;
return $field_$.Get(); return $field_$.Get();
} }
inline void $Msg$::_internal_set_$name$(const std::string& value) { inline void $Msg$::_internal_set_$name_internal$(const std::string& value) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
$update_hasbit$; $update_hasbit$;
//~ Don't use $Set$ here; we always want the std::string variant //~ Don't use $Set$ here; we always want the std::string variant
//~ regardless of whether this is a `bytes` field. //~ regardless of whether this is a `bytes` field.
$field_$.Set(value, $set_args$); $field_$.Set(value, $set_args$);
} }
inline std::string* $Msg$::_internal_mutable_$name$() { inline std::string* $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
$update_hasbit$; $update_hasbit$;
return $field_$.Mutable($lazy_args$, $set_args$); return $field_$.Mutable($lazy_args$, $set_args$);
@ -505,7 +505,7 @@ void SingularString::GenerateInlineAccessorDefinitions(io::Printer* p) const {
if (is_inlined()) { if (is_inlined()) {
p->Emit(R"cc( p->Emit(R"cc(
inline bool $Msg$::_internal_$name$_donated() const { inline bool $Msg$::_internal_$name_internal$_donated() const {
return $inlined_string_donated$; return $inlined_string_donated$;
} }
)cc"); )cc");
@ -871,7 +871,7 @@ void RepeatedString::GenerateInlineAccessorDefinitions(io::Printer* p) const {
inline std::string* $Msg$::add_$name$() inline std::string* $Msg$::add_$name$()
ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_ATTRIBUTE_LIFETIME_BOUND {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
std::string* _s = _internal_mutable_$name$()->Add(); std::string* _s = _internal_mutable_$name_internal$()->Add();
$annotate_add_mutable$; $annotate_add_mutable$;
// @@protoc_insertion_point(field_add_mutable:$pkg.Msg.field$) // @@protoc_insertion_point(field_add_mutable:$pkg.Msg.field$)
return _s; return _s;
@ -880,72 +880,73 @@ void RepeatedString::GenerateInlineAccessorDefinitions(io::Printer* p) const {
ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_get$; $annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$) // @@protoc_insertion_point(field_get:$pkg.Msg.field$)
return _internal_$name$().$Get$(index$GetExtraArg$); return _internal_$name_internal$().$Get$(index$GetExtraArg$);
} }
inline std::string* $Msg$::mutable_$name$(int index) inline std::string* $Msg$::mutable_$name$(int index)
ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_mutable$; $annotate_mutable$;
// @@protoc_insertion_point(field_mutable:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable:$pkg.Msg.field$)
return _internal_mutable_$name$()->Mutable(index); return _internal_mutable_$name_internal$()->Mutable(index);
} }
inline void $Msg$::set_$name$(int index, const std::string& value) { inline void $Msg$::set_$name$(int index, const std::string& value) {
_internal_mutable_$name$()->Mutable(index)->assign(value); _internal_mutable_$name_internal$()->Mutable(index)->assign(value);
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set:$pkg.Msg.field$) // @@protoc_insertion_point(field_set:$pkg.Msg.field$)
} }
inline void $Msg$::set_$name$(int index, std::string&& value) { inline void $Msg$::set_$name$(int index, std::string&& value) {
_internal_mutable_$name$()->Mutable(index)->assign(std::move(value)); _internal_mutable_$name_internal$()->Mutable(index)->assign(std::move(value));
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set:$pkg.Msg.field$) // @@protoc_insertion_point(field_set:$pkg.Msg.field$)
} }
inline void $Msg$::set_$name$(int index, const char* value) { inline void $Msg$::set_$name$(int index, const char* value) {
$DCHK$(value != nullptr); $DCHK$(value != nullptr);
_internal_mutable_$name$()->Mutable(index)->assign(value); _internal_mutable_$name_internal$()->Mutable(index)->assign(value);
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set_char:$pkg.Msg.field$) // @@protoc_insertion_point(field_set_char:$pkg.Msg.field$)
} }
inline void $Msg$::set_$name$(int index, const $byte$* value, inline void $Msg$::set_$name$(int index, const $byte$* value,
std::size_t size) { std::size_t size) {
_internal_mutable_$name$()->Mutable(index)->assign( _internal_mutable_$name_internal$()->Mutable(index)->assign(
reinterpret_cast<const char*>(value), size); reinterpret_cast<const char*>(value), size);
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set_pointer:$pkg.Msg.field$) // @@protoc_insertion_point(field_set_pointer:$pkg.Msg.field$)
} }
inline void $Msg$::set_$name$(int index, absl::string_view value) { inline void $Msg$::set_$name$(int index, absl::string_view value) {
_internal_mutable_$name$()->Mutable(index)->assign(value.data(), _internal_mutable_$name_internal$()->Mutable(index)->assign(
value.size()); value.data(), value.size());
$annotate_set$; $annotate_set$;
// @@protoc_insertion_point(field_set_string_piece:$pkg.Msg.field$) // @@protoc_insertion_point(field_set_string_piece:$pkg.Msg.field$)
} }
inline void $Msg$::add_$name$(const std::string& value) { inline void $Msg$::add_$name$(const std::string& value) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
_internal_mutable_$name$()->Add()->assign(value); _internal_mutable_$name_internal$()->Add()->assign(value);
$annotate_add$; $annotate_add$;
// @@protoc_insertion_point(field_add:$pkg.Msg.field$) // @@protoc_insertion_point(field_add:$pkg.Msg.field$)
} }
inline void $Msg$::add_$name$(std::string&& value) { inline void $Msg$::add_$name$(std::string&& value) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
_internal_mutable_$name$()->Add(std::move(value)); _internal_mutable_$name_internal$()->Add(std::move(value));
$annotate_add$; $annotate_add$;
// @@protoc_insertion_point(field_add:$pkg.Msg.field$) // @@protoc_insertion_point(field_add:$pkg.Msg.field$)
} }
inline void $Msg$::add_$name$(const char* value) { inline void $Msg$::add_$name$(const char* value) {
$DCHK$(value != nullptr); $DCHK$(value != nullptr);
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
_internal_mutable_$name$()->Add()->assign(value); _internal_mutable_$name_internal$()->Add()->assign(value);
$annotate_add$; $annotate_add$;
// @@protoc_insertion_point(field_add_char:$pkg.Msg.field$) // @@protoc_insertion_point(field_add_char:$pkg.Msg.field$)
} }
inline void $Msg$::add_$name$(const $byte$* value, std::size_t size) { inline void $Msg$::add_$name$(const $byte$* value, std::size_t size) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
_internal_mutable_$name$()->Add()->assign( _internal_mutable_$name_internal$()->Add()->assign(
reinterpret_cast<const char*>(value), size); reinterpret_cast<const char*>(value), size);
$annotate_add$; $annotate_add$;
// @@protoc_insertion_point(field_add_pointer:$pkg.Msg.field$) // @@protoc_insertion_point(field_add_pointer:$pkg.Msg.field$)
} }
inline void $Msg$::add_$name$(absl::string_view value) { inline void $Msg$::add_$name$(absl::string_view value) {
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
_internal_mutable_$name$()->Add()->assign(value.data(), value.size()); _internal_mutable_$name_internal$()->Add()->assign(value.data(),
value.size());
$annotate_add$; $annotate_add$;
// @@protoc_insertion_point(field_add_string_piece:$pkg.Msg.field$) // @@protoc_insertion_point(field_add_string_piece:$pkg.Msg.field$)
} }
@ -953,24 +954,25 @@ void RepeatedString::GenerateInlineAccessorDefinitions(io::Printer* p) const {
$Msg$::$name$() const ABSL_ATTRIBUTE_LIFETIME_BOUND { $Msg$::$name$() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_list$; $annotate_list$;
// @@protoc_insertion_point(field_list:$pkg.Msg.field$) // @@protoc_insertion_point(field_list:$pkg.Msg.field$)
return _internal_$name$(); return _internal_$name_internal$();
} }
inline ::$proto_ns$::RepeatedPtrField<std::string>* inline ::$proto_ns$::RepeatedPtrField<std::string>*
$Msg$::mutable_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND { $Msg$::mutable_$name$() ABSL_ATTRIBUTE_LIFETIME_BOUND {
$annotate_mutable_list$; $annotate_mutable_list$;
// @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$) // @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$)
$TsanDetectConcurrentMutation$; $TsanDetectConcurrentMutation$;
return _internal_mutable_$name$(); return _internal_mutable_$name_internal$();
} }
)cc"); )cc");
if (ShouldSplit(descriptor_, options_)) { if (ShouldSplit(descriptor_, options_)) {
p->Emit(R"cc( p->Emit(R"cc(
inline const $pb$::RepeatedPtrField<std::string>& inline const $pb$::RepeatedPtrField<std::string>&
$Msg$::_internal_$name$() const { $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return *$field_$; return *$field_$;
} }
inline $pb$::RepeatedPtrField<std::string>* $Msg$::_internal_mutable_$name$() { inline $pb$::RepeatedPtrField<std::string>*
$Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
$PrepareSplitMessageForWrite$; $PrepareSplitMessageForWrite$;
if ($field_$.IsDefault()) { if ($field_$.IsDefault()) {
@ -984,12 +986,12 @@ void RepeatedString::GenerateInlineAccessorDefinitions(io::Printer* p) const {
} else { } else {
p->Emit(R"cc( p->Emit(R"cc(
inline const ::$proto_ns$::RepeatedPtrField<std::string>& inline const ::$proto_ns$::RepeatedPtrField<std::string>&
$Msg$::_internal_$name$() const { $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return $field_$; return $field_$;
} }
inline ::$proto_ns$::RepeatedPtrField<std::string>* inline ::$proto_ns$::RepeatedPtrField<std::string>*
$Msg$::_internal_mutable_$name$() { $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentRead$; $TsanDetectConcurrentRead$;
return &$field_$; return &$field_$;
} }

@ -29,6 +29,7 @@
#include "absl/log/absl_log.h" #include "absl/log/absl_log.h"
#include "absl/strings/ascii.h" #include "absl/strings/ascii.h"
#include "absl/strings/escaping.h" #include "absl/strings/escaping.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/strings/str_join.h" #include "absl/strings/str_join.h"
@ -1060,7 +1061,7 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field,
} }
if (HasInternalHasMethod(field)) { if (HasInternalHasMethod(field)) {
p->Emit(R"cc( p->Emit(R"cc(
inline bool $classname$::_internal_has_$name$() const { inline bool $classname$::_internal_has_$name_internal$() const {
return $has_field$; return $has_field$;
} }
)cc"); )cc");
@ -1068,7 +1069,7 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field,
// set_has_$name$() for oneof fields is always private; hence should not be // set_has_$name$() for oneof fields is always private; hence should not be
// annotated. // annotated.
p->Emit(R"cc( p->Emit(R"cc(
inline void $classname$::set_has_$name$() { inline void $classname$::set_has_$name_internal$() {
$oneof_case$[$oneof_index$] = k$field_name$; $oneof_case$[$oneof_index$] = k$field_name$;
} }
)cc"); )cc");
@ -1120,22 +1121,81 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field,
)cc"); )cc");
} }
namespace {
class AccessorVerifier {
public:
using SourceLocation = io::Printer::SourceLocation;
AccessorVerifier(const FieldDescriptor* field) : field_(field) {}
~AccessorVerifier() {
ABSL_CHECK(!needs_annotate_) << Error(SourceLocation::current());
}
void operator()(absl::string_view label, io::Printer::SourceLocation loc) {
if (label == "name" || label == "release_name") {
// All accessors use $name$ or $release_name$ when constructing the
// function name. We hook into those to determine that an accessor is
// starting.
ABSL_CHECK(!needs_annotate_) << Error(loc);
loc_ = loc;
needs_annotate_ = true;
} else if (absl::StartsWith(label, "annotate")) {
// All annotation labels start with `annotate`. Eg `annotate_get`.
ABSL_CHECK(needs_annotate_) << Error(loc);
loc_ = loc;
needs_annotate_ = false;
}
}
private:
std::string Error(SourceLocation loc) const {
return absl::StrFormat("Field %s printed from %s:%d (prev %s:%d)\n",
field_->full_name(), loc.file_name(), loc.line(),
loc_.file_name(), loc_.line());
}
bool needs_annotate_ = false;
// We keep these fields for error reporting.
const FieldDescriptor* field_;
// On error, we report two locations: the current one and the last one. This
// can help determine where the bug is. For example, if we see "name" twice in
// a row, the bug is likely in the "last" one and not the current one because
// it means the previous accessor didn't add the required code.
SourceLocation loc_;
};
} // namespace
void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* p) { void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* p) {
p->Emit("// $classname$\n\n"); p->Emit("// $classname$\n\n");
for (auto field : FieldRange(descriptor_)) { for (auto field : FieldRange(descriptor_)) {
// We use a print listener to verify that the field generators properly add
// the right annotations. This is only a verification step aimed to prevent
// bugs where we have lack of test coverage. Note that this will verify the
// annotations even when the particular feature is not on because we look at
// the substitution variables, not the substitution result.
// The check is a state machine that verifies that every substitution for
// `name` is followed by one and only one for needed annotations. False
// positives are accessors that are using $name$ for an internal name. For
// those you can use $name_internal$ which is the same substitution but not
// tracked by the verifier.
const auto accessor_verifier =
p->WithSubstitutionListener(AccessorVerifier(field));
PrintFieldComment(Formatter{p}, field, options_); PrintFieldComment(Formatter{p}, field, options_);
auto v = p->WithVars(FieldVars(field, options_)); auto v = p->WithVars(FieldVars(field, options_));
auto t = p->WithVars(MakeTrackerCalls(field, options_)); auto t = p->WithVars(MakeTrackerCalls(field, options_));
if (field->is_repeated()) { if (field->is_repeated()) {
p->Emit(R"cc( p->Emit(R"cc(
inline int $classname$::_internal_$name$_size() const { inline int $classname$::_internal_$name_internal$_size() const {
return _internal_$name$().size(); return _internal_$name_internal$().size();
} }
inline int $classname$::$name$_size() const { inline int $classname$::$name$_size() const {
$annotate_size$; $annotate_size$;
return _internal_$name$_size(); return _internal_$name_internal$_size();
} }
)cc"); )cc");
} else if (field->real_containing_oneof()) { } else if (field->real_containing_oneof()) {

@ -1295,8 +1295,8 @@ inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* va
// @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
} }
inline void CodeGeneratorRequest::set_file_to_generate(int index, absl::string_view value) { inline void CodeGeneratorRequest::set_file_to_generate(int index, absl::string_view value) {
_internal_mutable_file_to_generate()->Mutable(index)->assign(value.data(), _internal_mutable_file_to_generate()->Mutable(index)->assign(
value.size()); value.data(), value.size());
// @@protoc_insertion_point(field_set_string_piece:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) // @@protoc_insertion_point(field_set_string_piece:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
} }
inline void CodeGeneratorRequest::add_file_to_generate(const std::string& value) { inline void CodeGeneratorRequest::add_file_to_generate(const std::string& value) {
@ -1323,7 +1323,8 @@ inline void CodeGeneratorRequest::add_file_to_generate(const char* value, std::s
} }
inline void CodeGeneratorRequest::add_file_to_generate(absl::string_view value) { inline void CodeGeneratorRequest::add_file_to_generate(absl::string_view value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_internal_mutable_file_to_generate()->Add()->assign(value.data(), value.size()); _internal_mutable_file_to_generate()->Add()->assign(value.data(),
value.size());
// @@protoc_insertion_point(field_add_string_piece:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) // @@protoc_insertion_point(field_add_string_piece:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
} }
inline const ::google::protobuf::RepeatedPtrField<std::string>& inline const ::google::protobuf::RepeatedPtrField<std::string>&

@ -10783,8 +10783,8 @@ inline void FileDescriptorProto::set_dependency(int index, const char* value,
// @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency) // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency)
} }
inline void FileDescriptorProto::set_dependency(int index, absl::string_view value) { inline void FileDescriptorProto::set_dependency(int index, absl::string_view value) {
_internal_mutable_dependency()->Mutable(index)->assign(value.data(), _internal_mutable_dependency()->Mutable(index)->assign(
value.size()); value.data(), value.size());
// @@protoc_insertion_point(field_set_string_piece:google.protobuf.FileDescriptorProto.dependency) // @@protoc_insertion_point(field_set_string_piece:google.protobuf.FileDescriptorProto.dependency)
} }
inline void FileDescriptorProto::add_dependency(const std::string& value) { inline void FileDescriptorProto::add_dependency(const std::string& value) {
@ -10811,7 +10811,8 @@ inline void FileDescriptorProto::add_dependency(const char* value, std::size_t s
} }
inline void FileDescriptorProto::add_dependency(absl::string_view value) { inline void FileDescriptorProto::add_dependency(absl::string_view value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_internal_mutable_dependency()->Add()->assign(value.data(), value.size()); _internal_mutable_dependency()->Add()->assign(value.data(),
value.size());
// @@protoc_insertion_point(field_add_string_piece:google.protobuf.FileDescriptorProto.dependency) // @@protoc_insertion_point(field_add_string_piece:google.protobuf.FileDescriptorProto.dependency)
} }
inline const ::google::protobuf::RepeatedPtrField<std::string>& inline const ::google::protobuf::RepeatedPtrField<std::string>&
@ -10871,8 +10872,8 @@ inline ::google::protobuf::RepeatedField<::int32_t>* FileDescriptorProto::mutabl
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_public_dependency(); return _internal_mutable_public_dependency();
} }
inline const ::google::protobuf::RepeatedField<::int32_t>& FileDescriptorProto::_internal_public_dependency() inline const ::google::protobuf::RepeatedField<::int32_t>&
const { FileDescriptorProto::_internal_public_dependency() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.public_dependency_; return _impl_.public_dependency_;
} }
@ -10916,8 +10917,8 @@ inline ::google::protobuf::RepeatedField<::int32_t>* FileDescriptorProto::mutabl
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_weak_dependency(); return _internal_mutable_weak_dependency();
} }
inline const ::google::protobuf::RepeatedField<::int32_t>& FileDescriptorProto::_internal_weak_dependency() inline const ::google::protobuf::RepeatedField<::int32_t>&
const { FileDescriptorProto::_internal_weak_dependency() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.weak_dependency_; return _impl_.weak_dependency_;
} }
@ -12192,8 +12193,8 @@ inline void DescriptorProto::set_reserved_name(int index, const char* value,
// @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name) // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name)
} }
inline void DescriptorProto::set_reserved_name(int index, absl::string_view value) { inline void DescriptorProto::set_reserved_name(int index, absl::string_view value) {
_internal_mutable_reserved_name()->Mutable(index)->assign(value.data(), _internal_mutable_reserved_name()->Mutable(index)->assign(
value.size()); value.data(), value.size());
// @@protoc_insertion_point(field_set_string_piece:google.protobuf.DescriptorProto.reserved_name) // @@protoc_insertion_point(field_set_string_piece:google.protobuf.DescriptorProto.reserved_name)
} }
inline void DescriptorProto::add_reserved_name(const std::string& value) { inline void DescriptorProto::add_reserved_name(const std::string& value) {
@ -12220,7 +12221,8 @@ inline void DescriptorProto::add_reserved_name(const char* value, std::size_t si
} }
inline void DescriptorProto::add_reserved_name(absl::string_view value) { inline void DescriptorProto::add_reserved_name(absl::string_view value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_internal_mutable_reserved_name()->Add()->assign(value.data(), value.size()); _internal_mutable_reserved_name()->Add()->assign(value.data(),
value.size());
// @@protoc_insertion_point(field_add_string_piece:google.protobuf.DescriptorProto.reserved_name) // @@protoc_insertion_point(field_add_string_piece:google.protobuf.DescriptorProto.reserved_name)
} }
inline const ::google::protobuf::RepeatedPtrField<std::string>& inline const ::google::protobuf::RepeatedPtrField<std::string>&
@ -13847,8 +13849,8 @@ inline void EnumDescriptorProto::set_reserved_name(int index, const char* value,
// @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.reserved_name) // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.reserved_name)
} }
inline void EnumDescriptorProto::set_reserved_name(int index, absl::string_view value) { inline void EnumDescriptorProto::set_reserved_name(int index, absl::string_view value) {
_internal_mutable_reserved_name()->Mutable(index)->assign(value.data(), _internal_mutable_reserved_name()->Mutable(index)->assign(
value.size()); value.data(), value.size());
// @@protoc_insertion_point(field_set_string_piece:google.protobuf.EnumDescriptorProto.reserved_name) // @@protoc_insertion_point(field_set_string_piece:google.protobuf.EnumDescriptorProto.reserved_name)
} }
inline void EnumDescriptorProto::add_reserved_name(const std::string& value) { inline void EnumDescriptorProto::add_reserved_name(const std::string& value) {
@ -13875,7 +13877,8 @@ inline void EnumDescriptorProto::add_reserved_name(const char* value, std::size_
} }
inline void EnumDescriptorProto::add_reserved_name(absl::string_view value) { inline void EnumDescriptorProto::add_reserved_name(absl::string_view value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_internal_mutable_reserved_name()->Add()->assign(value.data(), value.size()); _internal_mutable_reserved_name()->Add()->assign(value.data(),
value.size());
// @@protoc_insertion_point(field_add_string_piece:google.protobuf.EnumDescriptorProto.reserved_name) // @@protoc_insertion_point(field_add_string_piece:google.protobuf.EnumDescriptorProto.reserved_name)
} }
inline const ::google::protobuf::RepeatedPtrField<std::string>& inline const ::google::protobuf::RepeatedPtrField<std::string>&
@ -16489,7 +16492,8 @@ inline ::google::protobuf::RepeatedField<int>* FieldOptions::mutable_targets()
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_targets(); return _internal_mutable_targets();
} }
inline const ::google::protobuf::RepeatedField<int>& FieldOptions::_internal_targets() const { inline const ::google::protobuf::RepeatedField<int>& FieldOptions::_internal_targets()
const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.targets_; return _impl_.targets_;
} }
@ -18572,8 +18576,8 @@ inline ::google::protobuf::RepeatedField<::int32_t>* SourceCodeInfo_Location::mu
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_path(); return _internal_mutable_path();
} }
inline const ::google::protobuf::RepeatedField<::int32_t>& SourceCodeInfo_Location::_internal_path() inline const ::google::protobuf::RepeatedField<::int32_t>&
const { SourceCodeInfo_Location::_internal_path() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.path_; return _impl_.path_;
} }
@ -18617,8 +18621,8 @@ inline ::google::protobuf::RepeatedField<::int32_t>* SourceCodeInfo_Location::mu
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_span(); return _internal_mutable_span();
} }
inline const ::google::protobuf::RepeatedField<::int32_t>& SourceCodeInfo_Location::_internal_span() inline const ::google::protobuf::RepeatedField<::int32_t>&
const { SourceCodeInfo_Location::_internal_span() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.span_; return _impl_.span_;
} }
@ -18817,8 +18821,8 @@ inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, co
// @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
} }
inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, absl::string_view value) { inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, absl::string_view value) {
_internal_mutable_leading_detached_comments()->Mutable(index)->assign(value.data(), _internal_mutable_leading_detached_comments()->Mutable(index)->assign(
value.size()); value.data(), value.size());
// @@protoc_insertion_point(field_set_string_piece:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) // @@protoc_insertion_point(field_set_string_piece:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
} }
inline void SourceCodeInfo_Location::add_leading_detached_comments(const std::string& value) { inline void SourceCodeInfo_Location::add_leading_detached_comments(const std::string& value) {
@ -18845,7 +18849,8 @@ inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* v
} }
inline void SourceCodeInfo_Location::add_leading_detached_comments(absl::string_view value) { inline void SourceCodeInfo_Location::add_leading_detached_comments(absl::string_view value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_internal_mutable_leading_detached_comments()->Add()->assign(value.data(), value.size()); _internal_mutable_leading_detached_comments()->Add()->assign(value.data(),
value.size());
// @@protoc_insertion_point(field_add_string_piece:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) // @@protoc_insertion_point(field_add_string_piece:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
} }
inline const ::google::protobuf::RepeatedPtrField<std::string>& inline const ::google::protobuf::RepeatedPtrField<std::string>&
@ -18962,8 +18967,8 @@ inline ::google::protobuf::RepeatedField<::int32_t>* GeneratedCodeInfo_Annotatio
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_path(); return _internal_mutable_path();
} }
inline const ::google::protobuf::RepeatedField<::int32_t>& GeneratedCodeInfo_Annotation::_internal_path() inline const ::google::protobuf::RepeatedField<::int32_t>&
const { GeneratedCodeInfo_Annotation::_internal_path() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.path_; return _impl_.path_;
} }

@ -547,6 +547,9 @@ void Printer::PrintImpl(absl::string_view format,
// If we get this far, we can conclude the chunk is a substitution // If we get this far, we can conclude the chunk is a substitution
// variable; we rename the `chunk` variable to make this clear below. // variable; we rename the `chunk` variable to make this clear below.
absl::string_view var = chunk.text; absl::string_view var = chunk.text;
if (substitution_listener_ != nullptr) {
substitution_listener_(var, opts.loc.value_or(SourceLocation()));
}
if (opts.use_curly_brace_substitutions && if (opts.use_curly_brace_substitutions &&
absl::ConsumePrefix(&var, "{")) { absl::ConsumePrefix(&var, "{")) {
if (!Validate(var.size() == 1u, opts, if (!Validate(var.size() == 1u, opts,

@ -24,6 +24,7 @@
#include "absl/cleanup/cleanup.h" #include "absl/cleanup/cleanup.h"
#include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/functional/function_ref.h" #include "absl/functional/function_ref.h"
#include "absl/log/absl_check.h" #include "absl/log/absl_check.h"
#include "absl/meta/type_traits.h" #include "absl/meta/type_traits.h"
@ -449,8 +450,8 @@ class PROTOBUF_EXPORT Printer {
// released. // released.
struct SourceLocation { struct SourceLocation {
static SourceLocation current() { return {}; } static SourceLocation current() { return {}; }
absl::string_view file_name() { return "<unknown>"; } absl::string_view file_name() const { return "<unknown>"; }
int line() { return 0; } int line() const { return 0; }
}; };
static constexpr char kDefaultVariableDelimiter = '$'; static constexpr char kDefaultVariableDelimiter = '$';
@ -655,6 +656,18 @@ class PROTOBUF_EXPORT Printer {
void FormatInternal(absl::Span<const std::string> args, const Map& vars, void FormatInternal(absl::Span<const std::string> args, const Map& vars,
absl::string_view format); absl::string_view format);
// Injects a substitution listener for the lifetime of the RAII object
// returned.
// While the listener is active it will receive a callback on each
// substitution label found.
// This can be used to add basic verification on top of emit routines.
auto WithSubstitutionListener(
absl::AnyInvocable<void(absl::string_view, SourceLocation)> listener) {
ABSL_CHECK(substitution_listener_ == nullptr);
substitution_listener_ = std::move(listener);
return absl::MakeCleanup([this] { substitution_listener_ = nullptr; });
}
private: private:
struct PrintOptions; struct PrintOptions;
struct Format; struct Format;
@ -753,6 +766,11 @@ class PROTOBUF_EXPORT Printer {
std::function<absl::optional<AnnotationRecord>(absl::string_view)>> std::function<absl::optional<AnnotationRecord>(absl::string_view)>>
annotation_lookups_; annotation_lookups_;
// If set, we invoke this when we do a label substitution. This can be used to
// verify consistency of the generated code while we generate it.
absl::AnyInvocable<void(absl::string_view, SourceLocation)>
substitution_listener_;
// A map from variable name to [start, end) offsets in the output buffer. // A map from variable name to [start, end) offsets in the output buffer.
// //
// This stores the data looked up by GetSubstitutionRange(). // This stores the data looked up by GetSubstitutionRange().

@ -610,6 +610,35 @@ TEST_F(PrinterTest, EmitConsumeAfter) {
"};\n"); "};\n");
} }
TEST_F(PrinterTest, EmitWithSubstituionListener) {
std::vector<std::string> seen;
Printer printer(output());
const auto emit = [&] {
printer.Emit(
{
{"class", "Foo"},
Printer::Sub{"var", "int x;"}.WithSuffix(";"),
},
R"cc(
void $class$::foo() { $var$; }
void $class$::set_foo() { $var$; }
)cc");
};
emit();
EXPECT_THAT(seen, ElementsAre());
{
auto listener = printer.WithSubstitutionListener(
[&](auto label, auto loc) { seen.emplace_back(label); });
emit();
}
EXPECT_THAT(seen, ElementsAre("class", "var", "class", "var"));
// Still works after the listener is disconnected.
seen.clear();
emit();
EXPECT_THAT(seen, ElementsAre());
}
TEST_F(PrinterTest, EmitConditionalFunctionCall) { TEST_F(PrinterTest, EmitConditionalFunctionCall) {
{ {
Printer printer(output()); Printer printer(output());

Loading…
Cancel
Save