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"
// variable is replaced with "field_" everywhere.
{"name", FieldName(field)},
// Same as above, but represents internal use.
{"name_internal", FieldName(field)},
{"index", field->index()},
{"number", field->number()},

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

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

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

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

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

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

@ -29,6 +29,7 @@
#include "absl/log/absl_log.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
@ -1060,7 +1061,7 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field,
}
if (HasInternalHasMethod(field)) {
p->Emit(R"cc(
inline bool $classname$::_internal_has_$name$() const {
inline bool $classname$::_internal_has_$name_internal$() const {
return $has_field$;
}
)cc");
@ -1068,7 +1069,7 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field,
// set_has_$name$() for oneof fields is always private; hence should not be
// annotated.
p->Emit(R"cc(
inline void $classname$::set_has_$name$() {
inline void $classname$::set_has_$name_internal$() {
$oneof_case$[$oneof_index$] = k$field_name$;
}
)cc");
@ -1120,22 +1121,81 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field,
)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) {
p->Emit("// $classname$\n\n");
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_);
auto v = p->WithVars(FieldVars(field, options_));
auto t = p->WithVars(MakeTrackerCalls(field, options_));
if (field->is_repeated()) {
p->Emit(R"cc(
inline int $classname$::_internal_$name$_size() const {
return _internal_$name$().size();
inline int $classname$::_internal_$name_internal$_size() const {
return _internal_$name_internal$().size();
}
inline int $classname$::$name$_size() const {
$annotate_size$;
return _internal_$name$_size();
return _internal_$name_internal$_size();
}
)cc");
} 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)
}
inline void CodeGeneratorRequest::set_file_to_generate(int index, absl::string_view value) {
_internal_mutable_file_to_generate()->Mutable(index)->assign(value.data(),
value.size());
_internal_mutable_file_to_generate()->Mutable(index)->assign(
value.data(), value.size());
// @@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) {
@ -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) {
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)
}
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)
}
inline void FileDescriptorProto::set_dependency(int index, absl::string_view value) {
_internal_mutable_dependency()->Mutable(index)->assign(value.data(),
value.size());
_internal_mutable_dependency()->Mutable(index)->assign(
value.data(), value.size());
// @@protoc_insertion_point(field_set_string_piece:google.protobuf.FileDescriptorProto.dependency)
}
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) {
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)
}
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);
return _internal_mutable_public_dependency();
}
inline const ::google::protobuf::RepeatedField<::int32_t>& FileDescriptorProto::_internal_public_dependency()
const {
inline const ::google::protobuf::RepeatedField<::int32_t>&
FileDescriptorProto::_internal_public_dependency() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.public_dependency_;
}
@ -10916,8 +10917,8 @@ inline ::google::protobuf::RepeatedField<::int32_t>* FileDescriptorProto::mutabl
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_weak_dependency();
}
inline const ::google::protobuf::RepeatedField<::int32_t>& FileDescriptorProto::_internal_weak_dependency()
const {
inline const ::google::protobuf::RepeatedField<::int32_t>&
FileDescriptorProto::_internal_weak_dependency() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
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)
}
inline void DescriptorProto::set_reserved_name(int index, absl::string_view value) {
_internal_mutable_reserved_name()->Mutable(index)->assign(value.data(),
value.size());
_internal_mutable_reserved_name()->Mutable(index)->assign(
value.data(), value.size());
// @@protoc_insertion_point(field_set_string_piece:google.protobuf.DescriptorProto.reserved_name)
}
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) {
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)
}
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)
}
inline void EnumDescriptorProto::set_reserved_name(int index, absl::string_view value) {
_internal_mutable_reserved_name()->Mutable(index)->assign(value.data(),
value.size());
_internal_mutable_reserved_name()->Mutable(index)->assign(
value.data(), value.size());
// @@protoc_insertion_point(field_set_string_piece:google.protobuf.EnumDescriptorProto.reserved_name)
}
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) {
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)
}
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);
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);
return _impl_.targets_;
}
@ -18572,8 +18576,8 @@ inline ::google::protobuf::RepeatedField<::int32_t>* SourceCodeInfo_Location::mu
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_path();
}
inline const ::google::protobuf::RepeatedField<::int32_t>& SourceCodeInfo_Location::_internal_path()
const {
inline const ::google::protobuf::RepeatedField<::int32_t>&
SourceCodeInfo_Location::_internal_path() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.path_;
}
@ -18617,8 +18621,8 @@ inline ::google::protobuf::RepeatedField<::int32_t>* SourceCodeInfo_Location::mu
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_span();
}
inline const ::google::protobuf::RepeatedField<::int32_t>& SourceCodeInfo_Location::_internal_span()
const {
inline const ::google::protobuf::RepeatedField<::int32_t>&
SourceCodeInfo_Location::_internal_span() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
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)
}
inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, absl::string_view value) {
_internal_mutable_leading_detached_comments()->Mutable(index)->assign(value.data(),
value.size());
_internal_mutable_leading_detached_comments()->Mutable(index)->assign(
value.data(), value.size());
// @@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) {
@ -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) {
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)
}
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);
return _internal_mutable_path();
}
inline const ::google::protobuf::RepeatedField<::int32_t>& GeneratedCodeInfo_Annotation::_internal_path()
const {
inline const ::google::protobuf::RepeatedField<::int32_t>&
GeneratedCodeInfo_Annotation::_internal_path() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
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
// variable; we rename the `chunk` variable to make this clear below.
absl::string_view var = chunk.text;
if (substitution_listener_ != nullptr) {
substitution_listener_(var, opts.loc.value_or(SourceLocation()));
}
if (opts.use_curly_brace_substitutions &&
absl::ConsumePrefix(&var, "{")) {
if (!Validate(var.size() == 1u, opts,

@ -24,6 +24,7 @@
#include "absl/cleanup/cleanup.h"
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/functional/function_ref.h"
#include "absl/log/absl_check.h"
#include "absl/meta/type_traits.h"
@ -449,8 +450,8 @@ class PROTOBUF_EXPORT Printer {
// released.
struct SourceLocation {
static SourceLocation current() { return {}; }
absl::string_view file_name() { return "<unknown>"; }
int line() { return 0; }
absl::string_view file_name() const { return "<unknown>"; }
int line() const { return 0; }
};
static constexpr char kDefaultVariableDelimiter = '$';
@ -655,6 +656,18 @@ class PROTOBUF_EXPORT Printer {
void FormatInternal(absl::Span<const std::string> args, const Map& vars,
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:
struct PrintOptions;
struct Format;
@ -753,6 +766,11 @@ class PROTOBUF_EXPORT Printer {
std::function<absl::optional<AnnotationRecord>(absl::string_view)>>
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.
//
// This stores the data looked up by GetSubstitutionRange().

@ -610,6 +610,35 @@ TEST_F(PrinterTest, EmitConsumeAfter) {
"};\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) {
{
Printer printer(output());

Loading…
Cancel
Save