@ -41,6 +41,7 @@
# include "google/protobuf/compiler/versions.h"
# include "google/protobuf/descriptor.h"
# include "google/protobuf/descriptor.pb.h"
# include "google/protobuf/dynamic_message.h"
# include "google/protobuf/io/printer.h"
// Must be last.
@ -480,6 +481,7 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* p) {
# include $h_include$
# include <algorithm>
# include <type_traits>
) " );
IncludeFile ( " third_party/protobuf/io/coded_stream.h " , p ) ;
@ -835,20 +837,26 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* p) {
}
void FileGenerator : : GenerateStaticInitializer ( io : : Printer * p ) {
if ( static_initializers_ . empty ( ) ) return ;
p - > Emit ( { { " expr " ,
[ & ] {
for ( auto & init : static_initializers_ ) {
init ( p ) ;
}
} } } ,
R " cc(
PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
static : : std : : false_type _static_init_ PROTOBUF_UNUSED =
( $ expr $ , : : std : : false_type { } ) ;
) cc " );
// Reset the vector because we might be generating many files.
static_initializers_ . clear ( ) ;
int priority = 0 ;
for ( auto & inits : static_initializers_ ) {
+ + priority ;
if ( inits . empty ( ) ) continue ;
p - > Emit (
{ { " priority " , priority } ,
{ " expr " ,
[ & ] {
for ( auto & init : inits ) {
init ( p ) ;
}
} } } ,
R " cc(
PROTOBUF_ATTRIBUTE_INIT_PRIORITY $ priority $ static : : std : : false_type
_static_init $ priority $ _ PROTOBUF_UNUSED =
( $ expr $ , : : std : : false_type { } ) ;
) cc " );
// Reset the vector because we might be generating many files.
inits . clear ( ) ;
}
}
void FileGenerator : : GenerateSourceForExtension ( int idx , io : : Printer * p ) {
@ -858,9 +866,13 @@ void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* p) {
NamespaceOpener ns ( Namespace ( file_ , options_ ) , p ) ;
extension_generators_ [ idx ] - > GenerateDefinition ( p ) ;
static_initializers_ . push_back ( [ this , idx ] ( auto * p ) {
extension_generators_ [ idx ] - > GenerateRegistration ( p ) ;
} ) ;
for ( auto priority : { kInitPriority101 , kInitPriority102 } ) {
if ( extension_generators_ [ idx ] - > WillGenerateRegistration ( priority ) ) {
static_initializers_ [ priority ] . push_back ( [ this , idx , priority ] ( auto * p ) {
extension_generators_ [ idx ] - > GenerateRegistration ( p , priority ) ;
} ) ;
}
}
GenerateStaticInitializer ( p ) ;
}
@ -989,9 +1001,14 @@ void FileGenerator::GenerateSource(io::Printer* p) {
for ( int i = 0 ; i < extension_generators_ . size ( ) ; + + i ) {
extension_generators_ [ i ] - > GenerateDefinition ( p ) ;
if ( ! is_lazily_init ) {
static_initializers_ . push_back ( [ & , i ] ( auto * p ) {
extension_generators_ [ i ] - > GenerateRegistration ( p ) ;
} ) ;
for ( auto priority : { kInitPriority101 , kInitPriority102 } ) {
if ( extension_generators_ [ i ] - > WillGenerateRegistration ( priority ) ) {
static_initializers_ [ priority ] . push_back (
[ this , i , priority ] ( auto * p ) {
extension_generators_ [ i ] - > GenerateRegistration ( p , priority ) ;
} ) ;
}
}
}
}
@ -1020,9 +1037,69 @@ void FileGenerator::GenerateSource(io::Printer* p) {
IncludeFile ( " third_party/protobuf/port_undef.inc " , p ) ;
}
static void GatherAllCustomOptionTypes (
const FileDescriptor * file ,
absl : : btree_map < absl : : string_view , const Descriptor * > & out ) {
const DescriptorPool * pool = file - > pool ( ) ;
const Descriptor * fd_proto_descriptor = pool - > FindMessageTypeByName (
FileDescriptorProto : : descriptor ( ) - > full_name ( ) ) ;
// Not all pools have descriptor.proto in them. In these cases there for sure
// are no custom options.
if ( fd_proto_descriptor = = nullptr ) {
return ;
}
// It's easier to inspect file as a proto, because we can use reflection on
// the proto to iterate over all content.
// However, we can't use the generated proto linked into the proto compiler
// for this, since it doesn't know the extensions that are potentially present
// the protos that are being compiled.
// Use a dynamic one from the correct pool to parse them.
DynamicMessageFactory factory ( pool ) ;
std : : unique_ptr < Message > fd_proto (
factory . GetPrototype ( fd_proto_descriptor ) - > New ( ) ) ;
{
FileDescriptorProto linkedin_fd_proto ;
file - > CopyTo ( & linkedin_fd_proto ) ;
ABSL_CHECK (
fd_proto - > ParseFromString ( linkedin_fd_proto . SerializeAsString ( ) ) ) ;
}
// Now find all the messages used, recursively.
std : : vector < const Message * > to_process = { fd_proto . get ( ) } ;
while ( ! to_process . empty ( ) ) {
const Message & msg = * to_process . back ( ) ;
to_process . pop_back ( ) ;
std : : vector < const FieldDescriptor * > fields ;
const Reflection & reflection = * msg . GetReflection ( ) ;
reflection . ListFields ( msg , & fields ) ;
for ( auto * field : fields ) {
const auto * field_msg = field - > message_type ( ) ;
if ( field_msg = = nullptr ) continue ;
if ( field - > is_extension ( ) ) {
const Descriptor * desc = msg . GetDescriptor ( ) ;
out [ desc - > full_name ( ) ] = desc ;
out [ field_msg - > full_name ( ) ] = field_msg ;
}
if ( field - > is_repeated ( ) ) {
for ( int i = 0 ; i < reflection . FieldSize ( msg , field ) ; i + + ) {
to_process . push_back ( & reflection . GetRepeatedMessage ( msg , field , i ) ) ;
}
} else {
to_process . push_back ( & reflection . GetMessage ( msg , field ) ) ;
}
}
}
}
static std : : vector < const Descriptor * >
GetMessagesToPinGloballyForWeakDescriptors ( const FileDescriptor * file ) {
std : : vector < const Descriptor * > out ;
GetMessagesToPinGloballyForWeakDescriptors ( const FileDescriptor * file ,
const Options & options ) {
// Sorted map to dedup and to make deterministic.
absl : : btree_map < absl : : string_view , const Descriptor * > res ;
// For simplicity we force pin request/response messages for all
// services. The current implementation of services might not do
@ -1032,11 +1109,22 @@ GetMessagesToPinGloballyForWeakDescriptors(const FileDescriptor* file) {
auto * service = file - > service ( i ) ;
for ( int j = 0 ; j < service - > method_count ( ) ; + + j ) {
auto * method = service - > method ( j ) ;
out . push_back ( method - > input_type ( ) ) ;
out . push_back ( method - > output_type ( ) ) ;
res [ method - > input_type ( ) - > full_name ( ) ] = method - > input_type ( ) ;
res [ method - > output_type ( ) - > full_name ( ) ] = method - > output_type ( ) ;
}
}
// For correctness, we must ensure that all messages used as custom options in
// the descriptor are pinned. Otherwise, we can't properly parse the
// descriptor.
GatherAllCustomOptionTypes ( file , res ) ;
std : : vector < const Descriptor * > out ;
for ( auto & p : res ) {
// We don't need to pin the bootstrap types. It is wasteful.
if ( IsBootstrapProto ( options , p . second - > file ( ) ) ) continue ;
out . push_back ( p . second ) ;
}
return out ;
}
@ -1266,8 +1354,10 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* p) {
// Descriptor initialization will still be performed lazily when it's needed.
if ( ! IsLazilyInitializedFile ( file_ - > name ( ) ) ) {
if ( UsingImplicitWeakDescriptor ( file_ , options_ ) ) {
for ( auto * pinned : GetMessagesToPinGloballyForWeakDescriptors ( file_ ) ) {
static_initializers_ . push_back ( [ this , pinned ] ( auto * p ) {
for ( auto * pinned :
GetMessagesToPinGloballyForWeakDescriptors ( file_ , options_ ) ) {
static_initializers_ [ kInitPriority102 ] . push_back ( [ this ,
pinned ] ( auto * p ) {
p - > Emit ( { { " pin " , StrongReferenceToType ( pinned , options_ ) } } ,
R " cc(
$ pin $ ,
@ -1275,7 +1365,7 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* p) {
} ) ;
}
}
static_initializers_ . push_back ( [ ] ( auto * p ) {
static_initializers_ [ kInitPriority102 ] . push_back ( [ ] ( auto * p ) {
p - > Emit ( R " cc(
: : _pbi : : AddDescriptors ( & $ desc_table $ ) ,
) cc " );