First steps towards a pure field generator interface.

Currently, FieldGenerator holds onto a bit of state, and due to the way its interface is constructed it results in untracked dependencies between the contents of map<string, string> values that get tossed around the compiler. In order to break these dependencies, we want to move calculation of string variables into a centrally tracked place, but that requires inserting variable setup and destruction code in each FieldGenerator call.

Hence, FieldGenerator is replaced with a PIMPL wrapper (FieldGenWrapper) to allow us to do this. Followup CLs will:
* Rename FieldGenWrapper to FieldGenerator and FieldGenerator to some interface-ey name.
* Gradually morph the interface of FieldGenerator to encapsulate all per-field logic, so that message.cc does not have to iterate over fields except to call into generators, and as such does not need to manipulate per-field substitution variables.

This CL is a no-op refactor.

PiperOrigin-RevId: 496489306
pull/11367/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent ebfba7b910
commit 6c7ac8ea46
  1. 67
      src/file_lists.cmake
  2. 101
      src/google/protobuf/compiler/cpp/field.cc
  3. 437
      src/google/protobuf/compiler/cpp/field.h
  4. 35
      src/google/protobuf/compiler/cpp/message.cc
  5. 6
      src/google/protobuf/compiler/cpp/primitive_field.cc
  6. 6
      src/google/protobuf/compiler/cpp/primitive_field.h
  7. 6
      src/google/protobuf/compiler/cpp/string_field.cc
  8. 6
      src/google/protobuf/compiler/cpp/string_field.h

@ -1,4 +1,4 @@
# Auto-generated by @//pkg:gen_src_file_lists_cmake
# Auto-generated by //pkg:gen_src_file_lists_cmake
#
# This file contains lists of sources based on Bazel rules. It should
# be included from a hand-written CMake file that defines targets.
@ -9,7 +9,7 @@ if(${CMAKE_VERSION} VERSION_GREATER 3.10 OR ${CMAKE_VERSION} VERSION_EQUAL 3.10)
include_guard()
endif()
# @//pkg:protobuf
# //pkg:protobuf
set(libprotobuf_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/any.pb.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/api.pb.cc
@ -85,7 +85,7 @@ set(libprotobuf_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.cc
)
# @//pkg:protobuf
# //pkg:protobuf
set(libprotobuf_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/any.pb.h
${protobuf_SOURCE_DIR}/src/google/protobuf/api.pb.h
@ -192,7 +192,7 @@ set(libprotobuf_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.h
)
# @//pkg:protobuf_lite
# //pkg:protobuf_lite
set(libprotobuf_lite_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc
@ -220,7 +220,7 @@ set(libprotobuf_lite_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.cc
)
# @//pkg:protobuf_lite
# //pkg:protobuf_lite
set(libprotobuf_lite_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/any.h
${protobuf_SOURCE_DIR}/src/google/protobuf/arena.h
@ -270,7 +270,7 @@ set(libprotobuf_lite_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.h
)
# @//pkg:protoc
# //pkg:protoc
set(libprotoc_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.cc
@ -366,7 +366,7 @@ set(libprotoc_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.cc
)
# @//pkg:protoc
# //pkg:protoc
set(libprotoc_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.h
@ -388,7 +388,6 @@ set(libprotoc_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/primitive_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/service.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/string_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/tracker.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_doc_comment.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum_field.h
@ -470,7 +469,7 @@ set(libprotoc_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.h
)
# @//src/google/protobuf:well_known_type_protos
# //src/google/protobuf:well_known_type_protos
set(wkt_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/any.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/api.proto
@ -484,68 +483,68 @@ set(wkt_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/wrappers.proto
)
# @//src/google/protobuf:descriptor_proto
# //src/google/protobuf:descriptor_proto
set(descriptor_proto_proto_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto
)
# @//src/google/protobuf:descriptor_proto
# //src/google/protobuf:descriptor_proto
set(descriptor_proto_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto.pb.cc
)
# @//src/google/protobuf:descriptor_proto
# //src/google/protobuf:descriptor_proto
set(descriptor_proto_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto.pb.h
)
# @//src/google/protobuf:descriptor_proto
# //src/google/protobuf:descriptor_proto
set(descriptor_proto_files
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_proto-descriptor-set.proto.bin
)
# @//src/google/protobuf/compiler:plugin_proto
# //src/google/protobuf/compiler:plugin_proto
set(plugin_proto_proto_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto
)
# @//src/google/protobuf/compiler:plugin_proto
# //src/google/protobuf/compiler:plugin_proto
set(plugin_proto_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto.pb.cc
)
# @//src/google/protobuf/compiler:plugin_proto
# //src/google/protobuf/compiler:plugin_proto
set(plugin_proto_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto.pb.h
)
# @//src/google/protobuf/compiler:plugin_proto
# //src/google/protobuf/compiler:plugin_proto
set(plugin_proto_files
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin_proto-descriptor-set.proto.bin
)
# @//pkg:common_test
# //pkg:common_test
set(common_test_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/testing/file.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/testing/googletest.cc
)
# @//pkg:common_test
# //pkg:common_test
set(common_test_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/testing/file.h
${protobuf_SOURCE_DIR}/src/google/protobuf/testing/googletest.h
)
# @//pkg:lite_test_util
# //pkg:lite_test_util
set(lite_test_util_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_test_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_test_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.cc
)
# @//pkg:lite_test_util
# //pkg:lite_test_util
set(lite_test_util_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_test_util.h
${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_test_util.h
@ -556,14 +555,14 @@ set(lite_test_util_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.h
)
# @//pkg:test_util
# //pkg:test_util
set(test_util_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.cc
)
# @//pkg:test_util
# //pkg:test_util
set(test_util_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/unittest.h
@ -578,7 +577,7 @@ set(test_util_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.inc
)
# @//src/google/protobuf:full_test_srcs
# //src/google/protobuf:full_test_srcs
set(protobuf_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align_test.cc
@ -610,7 +609,7 @@ set(protobuf_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.cc
)
# @//src/google/protobuf:test_proto_srcs
# //src/google/protobuf:test_proto_srcs
set(protobuf_test_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/map_proto2_unittest.proto
@ -643,13 +642,13 @@ set(protobuf_test_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_well_known_types.proto
)
# @//src/google/protobuf:lite_test_srcs
# //src/google/protobuf:lite_test_srcs
set(protobuf_lite_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/lite_arena_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/lite_unittest.cc
)
# @//src/google/protobuf:lite_test_proto_srcs
# //src/google/protobuf:lite_test_proto_srcs
set(protobuf_lite_test_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_unittest.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_import_lite.proto
@ -657,7 +656,7 @@ set(protobuf_lite_test_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_lite.proto
)
# @//src/google/protobuf/compiler:test_srcs
# //src/google/protobuf/compiler:test_srcs
set(compiler_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc
@ -680,18 +679,18 @@ set(compiler_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
)
# @//src/google/protobuf/compiler:test_proto_srcs
# //src/google/protobuf/compiler:test_proto_srcs
set(compiler_test_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/test_bad_identifiers.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
)
# @//src/google/protobuf/compiler:test_plugin_srcs
# //src/google/protobuf/compiler:test_plugin_srcs
set(test_plugin_files
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/test_plugin.cc
)
# @//src/google/protobuf/io:test_srcs
# //src/google/protobuf/io:test_srcs
set(io_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32_unittest.cc
@ -702,7 +701,7 @@ set(io_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_unittest.cc
)
# @//src/google/protobuf/util:test_srcs
# //src/google/protobuf/util:test_srcs
set(util_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator_test.cc
@ -712,14 +711,14 @@ set(util_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util_test.cc
)
# @//src/google/protobuf/util:test_proto_srcs
# //src/google/protobuf/util:test_proto_srcs
set(util_test_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format_proto3.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer_unittest.proto
)
# @//src/google/protobuf/stubs:test_srcs
# //src/google/protobuf/stubs:test_srcs
set(stubs_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/common_unittest.cc
)

@ -167,8 +167,8 @@ void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) {
"u");
}
void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const {
Formatter format(printer, variables_);
void FieldGenerator::GenerateAggregateInitializer(io::Printer* p) const {
Formatter format(p, variables_);
if (ShouldSplit(descriptor_, options_)) {
format("decltype(Impl_::Split::$name$_){arena}");
return;
@ -177,110 +177,97 @@ void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const {
}
void FieldGenerator::GenerateConstexprAggregateInitializer(
io::Printer* printer) const {
Formatter format(printer, variables_);
io::Printer* p) const {
Formatter format(p, variables_);
format("/*decltype($field$)*/{}");
}
void FieldGenerator::GenerateCopyAggregateInitializer(
io::Printer* printer) const {
Formatter format(printer, variables_);
void FieldGenerator::GenerateCopyAggregateInitializer(io::Printer* p) const {
Formatter format(p, variables_);
format("decltype($field$){from.$field$}");
}
void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const {
void FieldGenerator::GenerateCopyConstructorCode(io::Printer* p) const {
if (ShouldSplit(descriptor_, options_)) {
// There is no copy constructor for the `Split` struct, so we need to copy
// the value here.
Formatter format(printer, variables_);
Formatter format(p, variables_);
format("$field$ = from.$field$;\n");
}
}
void FieldGenerator::GenerateIfHasField(io::Printer* printer) const {
void FieldGenerator::GenerateIfHasField(io::Printer* p) const {
GOOGLE_ABSL_CHECK(internal::cpp::HasHasbit(descriptor_));
GOOGLE_ABSL_CHECK(variables_.find("has_hasbit") != variables_.end());
Formatter format(printer, variables_);
Formatter format(p, variables_);
format("if (($has_hasbit$) != 0) {\n");
}
FieldGenerator::~FieldGenerator() {}
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
const Options& options,
MessageSCCAnalyzer* scc_analyzer)
: descriptor_(descriptor), field_generators_(descriptor->field_count()) {
// Construct all the FieldGenerators.
for (int i = 0; i < descriptor->field_count(); i++) {
field_generators_[i].reset(
MakeGenerator(descriptor->field(i), options, scc_analyzer));
}
}
FieldGenerator* FieldGeneratorMap::MakeGoogleInternalGenerator(
const FieldDescriptor* field, const Options& options,
MessageSCCAnalyzer* scc_analyzer) {
return nullptr;
}
FieldGenerator* FieldGeneratorMap::MakeGenerator(
namespace {
std::unique_ptr<FieldGenerator> MakeGenerator(
const FieldDescriptor* field, const Options& options,
MessageSCCAnalyzer* scc_analyzer) {
FieldGenerator* generator =
MakeGoogleInternalGenerator(field, options, scc_analyzer);
if (generator) {
return generator;
}
if (field->is_repeated()) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
if (field->is_map()) {
return new MapFieldGenerator(field, options, scc_analyzer);
return absl::make_unique<MapFieldGenerator>(field, options,
scc_analyzer);
} else {
return new RepeatedMessageFieldGenerator(field, options,
scc_analyzer);
return absl::make_unique<RepeatedMessageFieldGenerator>(
field, options, scc_analyzer);
}
case FieldDescriptor::CPPTYPE_STRING:
return new RepeatedStringFieldGenerator(field, options);
return absl::make_unique<RepeatedStringFieldGenerator>(field, options);
case FieldDescriptor::CPPTYPE_ENUM:
return new RepeatedEnumFieldGenerator(field, options);
return absl::make_unique<RepeatedEnumFieldGenerator>(field, options);
default:
return new RepeatedPrimitiveFieldGenerator(field, options);
return absl::make_unique<RepeatedPrimitiveFieldGenerator>(field,
options);
}
} else if (field->real_containing_oneof()) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
return new MessageOneofFieldGenerator(field, options, scc_analyzer);
return absl::make_unique<MessageOneofFieldGenerator>(field, options,
scc_analyzer);
case FieldDescriptor::CPPTYPE_STRING:
return new StringOneofFieldGenerator(field, options);
return absl::make_unique<StringOneofFieldGenerator>(field, options);
case FieldDescriptor::CPPTYPE_ENUM:
return new EnumOneofFieldGenerator(field, options);
return absl::make_unique<EnumOneofFieldGenerator>(field, options);
default:
return new PrimitiveOneofFieldGenerator(field, options);
return absl::make_unique<PrimitiveOneofFieldGenerator>(field, options);
}
} else {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
return new MessageFieldGenerator(field, options, scc_analyzer);
return absl::make_unique<MessageFieldGenerator>(field, options,
scc_analyzer);
case FieldDescriptor::CPPTYPE_STRING:
return new StringFieldGenerator(field, options);
return absl::make_unique<StringFieldGenerator>(field, options);
case FieldDescriptor::CPPTYPE_ENUM:
return new EnumFieldGenerator(field, options);
return absl::make_unique<EnumFieldGenerator>(field, options);
default:
return new PrimitiveFieldGenerator(field, options);
return absl::make_unique<PrimitiveFieldGenerator>(field, options);
}
}
}
} // namespace
FieldGeneratorMap::~FieldGeneratorMap() {}
FieldGenWrapper::FieldGenWrapper(const FieldDescriptor* field,
const Options& options,
MessageSCCAnalyzer* scc_analyzer)
: impl_(MakeGenerator(field, options, scc_analyzer)) {}
const FieldGenerator& FieldGeneratorMap::get(
const FieldDescriptor* field) const {
GOOGLE_ABSL_CHECK_EQ(field->containing_type(), descriptor_);
return *field_generators_[field->index()];
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
const Options& options,
MessageSCCAnalyzer* scc_analyzer)
: descriptor_(descriptor) {
// Construct all the FieldGenerators.
fields_.reserve(descriptor->field_count());
for (const auto* field : internal::FieldRange(descriptor)) {
fields_.emplace_back(field, options, scc_analyzer);
}
}
} // namespace cpp

@ -38,6 +38,7 @@
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "google/protobuf/descriptor.h"
#include "absl/container/flat_hash_map.h"
@ -45,178 +46,73 @@
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/cpp/options.h"
namespace google {
namespace protobuf {
namespace io {
class Printer; // printer.h
}
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
absl::flat_hash_map<absl::string_view, std::string> FieldVars(
const FieldDescriptor* desc, const Options& opts);
absl::flat_hash_map<absl::string_view, std::string> OneofFieldVars(
const FieldDescriptor* descriptor);
// Helper function: set variables in the map that are the same for all
// field code generators.
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
// 'deprecation'].
void SetCommonFieldVariables(
const FieldDescriptor* descriptor,
absl::flat_hash_map<absl::string_view, std::string>* variables,
const Options& options);
void SetCommonOneofFieldVariables(
const FieldDescriptor* descriptor,
absl::flat_hash_map<absl::string_view, std::string>* variables);
// Customization points for each field codegen type. See FieldGenWrapper to
// see how each of these functions is used.
class FieldGenerator {
public:
explicit FieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
: descriptor_(descriptor), options_(options) {}
FieldGenerator(const FieldGenerator&) = delete;
FieldGenerator& operator=(const FieldGenerator&) = delete;
virtual ~FieldGenerator();
virtual void GenerateSerializeWithCachedSizes(
io::Printer* printer) const final{};
// Generate lines of code declaring members fields of the message class
// needed to represent this field. These are placed inside the message
// class.
virtual void GeneratePrivateMembers(io::Printer* printer) const = 0;
// Generate static default variable for this field. These are placed inside
// the message class. Most field types don't need this, so the default
// implementation is empty.
virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
// Generate prototypes for all of the accessor functions related to this
// field. These are placed inside the class definition.
virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;
// Generate inline definitions of accessor functions for this field.
// These are placed inside the header after all class definitions.
virtual void GenerateInlineAccessorDefinitions(
io::Printer* printer) const = 0;
// Generate definitions of accessors that aren't inlined. These are
// placed somewhere in the .cc file.
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateNonInlineAccessorDefinitions(
io::Printer* /*printer*/) const {}
// Generate declarations of accessors that are for internal purposes only.
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateInternalAccessorDefinitions(
io::Printer* /*printer*/) const {}
// Generate definitions of accessors that are for internal purposes only.
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateInternalAccessorDeclarations(
io::Printer* /*printer*/) const {}
// Generate lines of code (statements, not declarations) which clear the
// field. This is used to define the clear_$name$() method
virtual void GenerateClearingCode(io::Printer* printer) const = 0;
// Generate lines of code (statements, not declarations) which clear the
// field as part of the Clear() method for the whole message. For message
// types which have field presence bits, MessageGenerator::GenerateClear
// will have already checked the presence bits.
//
// Since most field types can re-use GenerateClearingCode, this method is
// not pure virtual.
virtual void GenerateMessageClearingCode(io::Printer* printer) const {
GenerateClearingCode(printer);
virtual ~FieldGenerator() = 0;
virtual void GeneratePrivateMembers(io::Printer* p) const = 0;
virtual void GenerateStaticMembers(io::Printer* p) const {}
virtual void GenerateAccessorDeclarations(io::Printer* p) const = 0;
virtual void GenerateInlineAccessorDefinitions(io::Printer* p) const = 0;
virtual void GenerateNonInlineAccessorDefinitions(io::Printer* p) const {}
virtual void GenerateInternalAccessorDefinitions(io::Printer* p) const {}
virtual void GenerateInternalAccessorDeclarations(io::Printer* p) const {}
virtual void GenerateClearingCode(io::Printer* p) const = 0;
virtual void GenerateMessageClearingCode(io::Printer* p) const {
GenerateClearingCode(p);
}
// Generate lines of code (statements, not declarations) which merges the
// contents of the field from the current message to the target message,
// which is stored in the generated code variable "from".
// This is used to fill in the MergeFrom method for the whole message.
// Details of this usage can be found in message.cc under the
// GenerateMergeFrom method.
virtual void GenerateMergingCode(io::Printer* printer) const = 0;
virtual void GenerateMergingCode(io::Printer* p) const = 0;
// Generates a copy constructor
virtual void GenerateCopyConstructorCode(io::Printer* printer) const;
virtual void GenerateCopyConstructorCode(io::Printer* p) const;
// Generate lines of code (statements, not declarations) which swaps
// this field and the corresponding field of another message, which
// is stored in the generated code variable "other". This is used to
// define the Swap method. Details of usage can be found in
// message.cc under the GenerateSwap method.
virtual void GenerateSwappingCode(io::Printer* printer) const = 0;
virtual void GenerateSwappingCode(io::Printer* p) const = 0;
// Generate initialization code for private members declared by
// GeneratePrivateMembers(). These go into the message class's SharedCtor()
// method, invoked by each of the generated constructors.
virtual void GenerateConstructorCode(io::Printer* printer) const = 0;
virtual void GenerateConstructorCode(io::Printer* p) const = 0;
// Generate any code that needs to go in the class's SharedDtor() method,
// invoked by the destructor.
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {}
// Generate a manual destructor invocation for use when the message is on an
// arena. The code that this method generates will be executed inside a
// shared-for-the-whole-message-class method registered with
// OwnDestructor().
virtual void GenerateArenaDestructorCode(io::Printer* printer) const {
virtual void GenerateDestructorCode(io::Printer* p) const {}
virtual void GenerateArenaDestructorCode(io::Printer* p) const {
GOOGLE_ABSL_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone)
<< descriptor_->cpp_type_name();
}
// Generate initialization code for private members declared by
// GeneratePrivateMembers(). These go into the SharedCtor's
// aggregate initialization of the _impl_ struct and must follow the syntax
// (e.g. `decltype($field$){$default$}`). Does not include `:` or `,`
// separators. Default values should be specified here when possible.
//
// Note: We use `decltype($field$)` for both explicit construction and the
// fact that it's self-documenting. Pre-C++17, copy elision isn't guaranteed
// in aggregate initialization so a valid copy/move constructor must exist
// (even though it's not used). Because of this, we need to comment out the
// decltype and fallback to implicit construction.
virtual void GenerateAggregateInitializer(io::Printer* printer) const;
// Generate constinit initialization code for private members declared by
// GeneratePrivateMembers(). These go into the constexpr constructor's
// aggregate initialization of the _impl_ struct and must follow the syntax
// (e.g. `/*decltype($field$)*/{}`, see above). Does not
// include `:` or `,` separators.
virtual void GenerateConstexprAggregateInitializer(
io::Printer* printer) const;
// Generate copy initialization code for private members declared by
// GeneratePrivateMembers(). These go into the copy constructor's
// aggregate initialization of the _impl_ struct and must follow the syntax
// (e.g. `decltype($field$){from.$field$}`, see above). Does not
// include `:` or `,` separators.
virtual void GenerateCopyAggregateInitializer(io::Printer* printer) const;
// Generate lines to serialize this field directly to the array "target",
// which are placed within the message's SerializeWithCachedSizesToArray()
// method. This must also advance "target" past the written bytes.
virtual void GenerateAggregateInitializer(io::Printer* p) const;
virtual void GenerateConstexprAggregateInitializer(io::Printer* p) const;
virtual void GenerateCopyAggregateInitializer(io::Printer* p) const;
virtual void GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const = 0;
io::Printer* p) const = 0;
// Generate lines to compute the serialized size of this field, which
// are placed in the message's ByteSize() method.
virtual void GenerateByteSize(io::Printer* printer) const = 0;
virtual void GenerateByteSize(io::Printer* p) const = 0;
// Generates lines to call IsInitialized() for eligible message fields. Non
// message fields won't need to override this function.
virtual void GenerateIsInitialized(io::Printer* printer) const {}
virtual void GenerateIsInitialized(io::Printer* p) const {}
virtual void GenerateIfHasField(io::Printer* printer) const;
virtual void GenerateIfHasField(io::Printer* p) const;
virtual bool IsInlined() const { return false; }
@ -228,46 +124,267 @@ class FieldGenerator {
void SetInlinedStringIndex(int32_t inlined_string_index);
protected:
// TODO(b/245791219): Remove these members and make this a pure interface.
const FieldDescriptor* descriptor_;
const Options& options_;
absl::flat_hash_map<absl::string_view, std::string> variables_;
};
inline FieldGenerator::~FieldGenerator() = default;
class FieldGenWrapper {
public:
FieldGenWrapper(const FieldDescriptor* field, const Options& options,
MessageSCCAnalyzer* scc_analyzer);
FieldGenWrapper(const FieldGenWrapper&) = delete;
FieldGenWrapper& operator=(const FieldGenWrapper&) = delete;
FieldGenWrapper(FieldGenWrapper&&) = default;
FieldGenWrapper& operator=(FieldGenWrapper&&) = default;
// Prints private members needed to represent this field.
//
// These are placed inside the class definition.
void GeneratePrivateMembers(io::Printer* p) const {
impl_->GeneratePrivateMembers(p);
}
// Prints static members needed to represent this field.
//
// These are placed inside the class definition.
void GenerateStaticMembers(io::Printer* p) const {
impl_->GenerateStaticMembers(p);
}
// Generates declarations for all of the accessor functions related to this
// field.
//
// These are placed inside the class definition.
void GenerateAccessorDeclarations(io::Printer* p) const {
impl_->GenerateAccessorDeclarations(p);
}
// Generates inline definitions of accessor functions for this field.
//
// These are placed in namespace scope in the header after all class
// definitions.
void GenerateInlineAccessorDefinitions(io::Printer* p) const {
impl_->GenerateInlineAccessorDefinitions(p);
}
// Generates definitions of accessors that aren't inlined.
//
// These are placed in namespace scope in the .cc file.
void GenerateNonInlineAccessorDefinitions(io::Printer* p) const {
impl_->GenerateNonInlineAccessorDefinitions(p);
}
// Generates declarations of accessors that are for internal purposes only.
void GenerateInternalAccessorDefinitions(io::Printer* p) const {
impl_->GenerateInternalAccessorDefinitions(p);
}
// Generates definitions of accessors that are for internal purposes only.
void GenerateInternalAccessorDeclarations(io::Printer* p) const {
impl_->GenerateInternalAccessorDeclarations(p);
}
// Generates statements which clear the field.
//
// This is used to define the clear_$name$() method.
void GenerateClearingCode(io::Printer* p) const {
impl_->GenerateClearingCode(p);
}
// Generates statements which clear the field as part of the Clear() method
// for the whole message.
//
// For message types which have field presence bits,
// MessageGenerator::GenerateClear will have already checked the presence
// bits.
void GenerateMessageClearingCode(io::Printer* p) const {
impl_->GenerateMessageClearingCode(p);
}
// Generates statements which merge the contents of the field from the current
// message to the target message, which is stored in the generated code
// variable `from`.
//
// This is used to fill in the MergeFrom method for the whole message.
//
// Details of this usage can be found in message.cc under the
// GenerateMergeFrom method.
void GenerateMergingCode(io::Printer* p) const {
impl_->GenerateMergingCode(p);
}
// Generates a copy constructor
//
// TODO(b/245791219): Document this properly.
void GenerateCopyConstructorCode(io::Printer* p) const {
impl_->GenerateCopyConstructorCode(p);
}
// Generates statements which swap this field and the corresponding field of
// another message, which is stored in the generated code variable `other`.
//
// This is used to define the Swap method. Details of usage can be found in
// message.cc under the GenerateSwap method.
void GenerateSwappingCode(io::Printer* p) const {
impl_->GenerateSwappingCode(p);
}
// Generates initialization code for private members declared by
// GeneratePrivateMembers().
//
// These go into the message class's SharedCtor() method, invoked by each of
// the generated constructors.
void GenerateConstructorCode(io::Printer* p) const {
impl_->GenerateConstructorCode(p);
}
// Generates any code that needs to go in the class's SharedDtor() method,
// invoked by the destructor.
void GenerateDestructorCode(io::Printer* p) const {
impl_->GenerateDestructorCode(p);
}
// Generates a manual destructor invocation for use when the message is on an
// arena.
//
// The code that this method generates will be executed inside a
// shared-for-the-whole-message-class method registered with OwnDestructor().
void GenerateArenaDestructorCode(io::Printer* p) const {
impl_->GenerateArenaDestructorCode(p);
}
// Generates initialization code for private members declared by
// GeneratePrivateMembers().
//
// These go into the SharedCtor's aggregate initialization of the _impl_
// struct and must follow the syntax `decltype($field$){$default$}`.
// Does not include `:` or `,` separators. Default values should be specified
// here when possible.
//
// NOTE: We use `decltype($field$)` for both explicit construction and the
// fact that it's self-documenting. Pre-C++17, copy elision isn't guaranteed
// in aggregate initialization so a valid copy/move constructor must exist
// (even though it's not used). Because of this, we need to comment out the
// decltype and fallback to implicit construction.
void GenerateAggregateInitializer(io::Printer* p) const {
impl_->GenerateAggregateInitializer(p);
}
// Generates constinit initialization code for private members declared by
// GeneratePrivateMembers().
//
// These go into the constexpr constructor's aggregate initialization of the
// _impl_ struct and must follow the syntax `/*decltype($field$)*/{}` (see
// above). Does not include `:` or `,` separators.
void GenerateConstexprAggregateInitializer(io::Printer* p) const {
impl_->GenerateConstexprAggregateInitializer(p);
}
// Generates copy initialization code for private members declared by
// GeneratePrivateMembers().
//
// These go into the copy constructor's aggregate initialization of the _impl_
// struct and must follow the syntax `decltype($field$){from.$field$}` (see
// above). Does not include `:` or `,` separators.
void GenerateCopyAggregateInitializer(io::Printer* p) const {
impl_->GenerateCopyAggregateInitializer(p);
}
// Generates statements to serialize this field directly to the array
// `target`, which are placed within the message's
// SerializeWithCachedSizesToArray() method.
//
// This must also advance `target` past the written bytes.
void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const {
impl_->GenerateSerializeWithCachedSizesToArray(p);
}
// Generates statements to compute the serialized size of this field, which
// are placed in the message's ByteSize() method.
void GenerateByteSize(io::Printer* p) const { impl_->GenerateByteSize(p); }
// Generates lines to call IsInitialized() for eligible message fields. Non
// message fields won't need to override this function.
void GenerateIsInitialized(io::Printer* p) const {
impl_->GenerateIsInitialized(p);
}
// TODO(b/245791219): Document this properly.
void GenerateIfHasField(io::Printer* p) const {
impl_->GenerateIfHasField(p);
}
// TODO(b/245791219): Document this properly.
bool IsInlined() const { return impl_->IsInlined(); }
// TODO(b/245791219): Document this properly.
ArenaDtorNeeds NeedsArenaDestructor() const {
return impl_->NeedsArenaDestructor();
}
private:
friend class FieldGeneratorMap;
std::unique_ptr<FieldGenerator> impl_;
};
// Convenience class which constructs FieldGenerators for a Descriptor.
class FieldGeneratorMap {
public:
FieldGeneratorMap(const Descriptor* descriptor, const Options& options,
MessageSCCAnalyzer* scc_analyzer);
FieldGeneratorMap(const FieldGeneratorMap&) = delete;
FieldGeneratorMap& operator=(const FieldGeneratorMap&) = delete;
~FieldGeneratorMap();
const FieldGenerator& get(const FieldDescriptor* field) const;
const FieldGenWrapper& get(const FieldDescriptor* field) const {
GOOGLE_ABSL_CHECK_EQ(field->containing_type(), descriptor_);
return fields_[field->index()];
}
void SetHasBitIndices(const std::vector<int>& has_bit_indices_) {
void SetHasBitIndices(absl::Span<const int> has_bit_indices) {
for (int i = 0; i < descriptor_->field_count(); ++i) {
field_generators_[i]->SetHasBitIndex(has_bit_indices_[i]);
fields_[i].impl_->SetHasBitIndex(has_bit_indices[i]);
}
}
void SetInlinedStringIndices(const std::vector<int>& inlined_string_indices) {
void SetInlinedStringIndices(absl::Span<const int> inlined_string_indices) {
for (int i = 0; i < descriptor_->field_count(); ++i) {
field_generators_[i]->SetInlinedStringIndex(inlined_string_indices[i]);
fields_[i].impl_->SetInlinedStringIndex(inlined_string_indices[i]);
}
}
private:
const Descriptor* descriptor_;
std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
static FieldGenerator* MakeGoogleInternalGenerator(
const FieldDescriptor* field, const Options& options,
MessageSCCAnalyzer* scc_analyzer);
static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
const Options& options,
MessageSCCAnalyzer* scc_analyzer);
std::vector<FieldGenWrapper> fields_;
};
// Helper function: set variables in the map that are the same for all
// field code generators.
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
// 'deprecation'].
//
// Each function comes in a legacy "write variables to an existing variable
// map" and a new version that returns a new map object for use with WithVars().
absl::flat_hash_map<absl::string_view, std::string> FieldVars(
const FieldDescriptor* desc, const Options& opts);
absl::flat_hash_map<absl::string_view, std::string> OneofFieldVars(
const FieldDescriptor* descriptor);
void SetCommonFieldVariables(
const FieldDescriptor* descriptor,
absl::flat_hash_map<absl::string_view, std::string>* variables,
const Options& options);
void SetCommonOneofFieldVariables(
const FieldDescriptor* descriptor,
absl::flat_hash_map<absl::string_view, std::string>* variables);
} // namespace cpp
} // namespace compiler
} // namespace protobuf

@ -1799,10 +1799,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) {
// Emit some private and static members
for (auto field : optimized_order_) {
const FieldGenerator& generator = field_generators_.get(field);
generator.GenerateStaticMembers(p);
field_generators_.get(field).GenerateStaticMembers(p);
if (!ShouldSplit(field, options_)) {
generator.GeneratePrivateMembers(p);
field_generators_.get(field).GeneratePrivateMembers(p);
}
}
if (ShouldSplit(descriptor_, options_)) {
@ -1810,8 +1809,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) {
format.Indent();
for (auto field : optimized_order_) {
if (!ShouldSplit(field, options_)) continue;
const FieldGenerator& generator = field_generators_.get(field);
generator.GeneratePrivateMembers(p);
field_generators_.get(field).GeneratePrivateMembers(p);
}
format.Outdent();
format(
@ -2503,8 +2501,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* p) {
for (auto field : optimized_order_) {
if (IsFieldStripped(field, options_) || ShouldSplit(field, options_))
continue;
const FieldGenerator& fg = field_generators_.get(field);
fg.GenerateArenaDestructorCode(p);
field_generators_.get(field).GenerateArenaDestructorCode(p);
}
if (ShouldSplit(descriptor_, options_)) {
format("if (!_this->IsSplitMessageDefault()) {\n");
@ -2512,8 +2509,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* p) {
for (auto field : optimized_order_) {
if (IsFieldStripped(field, options_) || !ShouldSplit(field, options_))
continue;
const FieldGenerator& fg = field_generators_.get(field);
fg.GenerateArenaDestructorCode(p);
field_generators_.get(field).GenerateArenaDestructorCode(p);
}
format.Outdent();
format("}\n");
@ -3405,7 +3401,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* p) {
// Go back and emit merging code for each of the fields we processed.
bool deferred_has_bit_changes = false;
for (const auto field : chunk) {
const FieldGenerator& generator = field_generators_.get(field);
const auto& generator = field_generators_.get(field);
if (field->is_repeated()) {
generator.GenerateMergingCode(p);
@ -3617,8 +3613,6 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* p,
PrintFieldComment(format, field);
}
const FieldGenerator& field_gen = field_generators_.get(field);
bool have_enclosing_if = false;
if (field->options().weak()) {
} else if (HasHasbit(field)) {
@ -3628,7 +3622,7 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* p,
if (cached_has_bits_index == has_bit_index / 32) {
format("if (cached_has_bits & $has_mask$) {\n");
} else {
field_gen.GenerateIfHasField(p);
field_generators_.get(field).GenerateIfHasField(p);
}
format.Indent();
@ -3637,7 +3631,7 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* p,
have_enclosing_if = EmitFieldNonDefaultCondition(p, "this->", field);
}
field_gen.GenerateSerializeWithCachedSizesToArray(p);
field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(p);
if (have_enclosing_if) {
format.Outdent();
@ -4063,12 +4057,11 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) {
format("::size_t total_size = 0;\n");
for (auto field : optimized_order_) {
if (field->is_required()) {
const FieldGenerator& field_gen = field_generators_.get(field);
format("\n");
field_gen.GenerateIfHasField(p);
field_generators_.get(field).GenerateIfHasField(p);
format.Indent();
PrintFieldComment(format, field);
field_gen.GenerateByteSize(p);
field_generators_.get(field).GenerateByteSize(p);
format.Outdent();
format("}\n");
}
@ -4122,10 +4115,9 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) {
for (auto field : optimized_order_) {
if (!field->is_required()) continue;
PrintFieldComment(format, field);
const FieldGenerator& field_gen = field_generators_.get(field);
field_gen.GenerateIfHasField(p);
field_generators_.get(field).GenerateIfHasField(p);
format.Indent();
field_gen.GenerateByteSize(p);
field_generators_.get(field).GenerateByteSize(p);
format.Outdent();
format("}\n");
}
@ -4180,7 +4172,6 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) {
// Go back and emit checks for each of the fields we processed.
for (int j = 0; j < chunk.size(); j++) {
const FieldDescriptor* field = chunk[j];
const FieldGenerator& generator = field_generators_.get(field);
bool have_enclosing_if = false;
bool need_extra_newline = false;
@ -4198,7 +4189,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) {
have_enclosing_if = EmitFieldNonDefaultCondition(p, "this->", field);
}
generator.GenerateByteSize(p);
field_generators_.get(field).GenerateByteSize(p);
if (have_enclosing_if) {
format.Outdent();

@ -135,8 +135,6 @@ PrimitiveFieldGenerator::PrimitiveFieldGenerator(
SetPrimitiveVariables(descriptor, &variables_, options);
}
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
void PrimitiveFieldGenerator::GeneratePrivateMembers(
io::Printer* printer) const {
Formatter format(printer, variables_);
@ -264,8 +262,6 @@ PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
SetCommonOneofFieldVariables(descriptor, &variables_);
}
PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions(
io::Printer* printer) const {
Formatter format(printer, variables_);
@ -328,8 +324,6 @@ RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
}
}
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
void RepeatedPrimitiveFieldGenerator::GeneratePrivateMembers(
io::Printer* printer) const {
Formatter format(printer, variables_);

@ -51,7 +51,7 @@ class PrimitiveFieldGenerator : public FieldGenerator {
const Options& options);
PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete;
PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete;
~PrimitiveFieldGenerator() override;
~PrimitiveFieldGenerator() override = default;
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const override;
@ -78,7 +78,7 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
PrimitiveOneofFieldGenerator(const PrimitiveOneofFieldGenerator&) = delete;
PrimitiveOneofFieldGenerator& operator=(const PrimitiveOneofFieldGenerator&) =
delete;
~PrimitiveOneofFieldGenerator() override;
~PrimitiveOneofFieldGenerator() override = default;
// implements FieldGenerator ---------------------------------------
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
@ -95,7 +95,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
delete;
RepeatedPrimitiveFieldGenerator& operator=(
const RepeatedPrimitiveFieldGenerator&) = delete;
~RepeatedPrimitiveFieldGenerator() override;
~RepeatedPrimitiveFieldGenerator() override = default;
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const override;

@ -108,8 +108,6 @@ StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
SetStringVariables(descriptor, &variables_, options);
}
StringFieldGenerator::~StringFieldGenerator() {}
void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
Formatter format(printer, variables_);
if (!inlined_) {
@ -579,8 +577,6 @@ StringOneofFieldGenerator::StringOneofFieldGenerator(
SetCommonOneofFieldVariables(descriptor, &variables_);
}
StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
io::Printer* printer) const {
Formatter format(printer, variables_);
@ -685,8 +681,6 @@ RepeatedStringFieldGenerator::RepeatedStringFieldGenerator(
SetStringVariables(descriptor, &variables_, options);
}
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
void RepeatedStringFieldGenerator::GeneratePrivateMembers(
io::Printer* printer) const {
Formatter format(printer, variables_);

@ -51,7 +51,7 @@ class StringFieldGenerator : public FieldGenerator {
const Options& options);
StringFieldGenerator(const StringFieldGenerator&) = delete;
StringFieldGenerator& operator=(const StringFieldGenerator&) = delete;
~StringFieldGenerator() override;
~StringFieldGenerator() override = default;
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const override;
@ -89,7 +89,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator {
StringOneofFieldGenerator(const StringOneofFieldGenerator&) = delete;
StringOneofFieldGenerator& operator=(const StringOneofFieldGenerator&) =
delete;
~StringOneofFieldGenerator() override;
~StringOneofFieldGenerator() override = default;
// implements FieldGenerator ---------------------------------------
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
@ -109,7 +109,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
RepeatedStringFieldGenerator(const RepeatedStringFieldGenerator&) = delete;
RepeatedStringFieldGenerator& operator=(const RepeatedStringFieldGenerator&) =
delete;
~RepeatedStringFieldGenerator() override;
~RepeatedStringFieldGenerator() override = default;
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const override;

Loading…
Cancel
Save