// Protocol Buffers - Google's data interchange format // Copyright 2023 Google LLC. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #include #include #include "google/protobuf/descriptor.upb.h" #include "absl/strings/escaping.h" #include "absl/strings/str_format.h" #include "absl/strings/str_join.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/io/printer.h" #include "upb/mem/arena.hpp" #include "upb/reflection/def.hpp" #include "upb/util/def_to_proto.h" #include "upb_generator/common/names.h" #include "upb_generator/minitable/names.h" #include "upb_generator/reflection/context.h" #include "upb_generator/reflection/header.h" #include "upb_generator/reflection/names.h" namespace upb::generator::reflection { namespace { using Sub = google::protobuf::io::Printer::Sub; static std::string DefSourceFilename(upb::FileDefPtr file) { return StripExtension(file.name()) + ".upbdefs.c"; } void WriteIncludes(upb::FileDefPtr file, Context& ctx) { ctx.Emit( { {"def_header_filename", DefHeaderFilename(file)}, {"mini_table_header_filename", MiniTableHeaderFilename(file.name())}, }, R"( #include "upb/reflection/def.h" #include "$def_header_filename$" #include "$mini_table_header_filename$" )"); } void WriteDefPoolFwdDecls(upb::FileDefPtr file, Context& ctx) { if (file.dependency_count() == 0) return; for (int i = 0; i < file.dependency_count(); i++) { ctx.Emit( {{"dllexport_decl", ctx.options().dllexport_decl}, {"def_init_symbol", ReflectionFileSymbol(file.dependency(i).name())}}, R"cc( extern$ dllexport_decl$ _upb_DefPool_Init $def_init_symbol$; )cc"); } ctx.Emit("\n"); } void WriteStringArrayLine(absl::string_view data, Context& ctx) { std::string line = absl::StrJoin(data, ", ", [](std::string* out, char ch) { absl::StrAppendFormat(out, "'%v'", absl::CEscape(absl::string_view(&ch, 1))); }); ctx.Emit({{"line", line}}, R"cc( $line$, )cc"); } void WriteStringArray(absl::string_view data, Context& ctx) { const size_t kMaxLineLength = 12; for (size_t i = 0; i < data.size(); i += kMaxLineLength) { WriteStringArrayLine(data.substr(i, kMaxLineLength), ctx); } } void WriteDescriptor(upb::FileDefPtr file, Context& ctx) { upb::Arena arena; google_protobuf_FileDescriptorProto* file_proto = upb_FileDef_ToProto(file.ptr(), arena.ptr()); size_t serialized_size; const char* serialized = google_protobuf_FileDescriptorProto_serialize( file_proto, arena.ptr(), &serialized_size); absl::string_view file_data(serialized, serialized_size); ctx.Emit({{"serialized_size", file_data.size()}, {"contents", [&] { WriteStringArray(file_data, ctx); }}}, R"cc( static const char descriptor[$serialized_size$] = { $contents$, }; )cc"); ctx.Emit("\n"); } void WriteDependencies(upb::FileDefPtr file, Context& ctx) { auto write_dep = [&](int i) { ctx.Emit({{"sym", ReflectionFileSymbol(file.dependency(i).name())}}, R"cc( &$sym$, )cc"); }; auto write_deps = [&] { for (int i = 0; i < file.dependency_count(); i++) write_dep(i); }; ctx.Emit({{"dep_count", file.dependency_count() + 1}, {google::protobuf::io::Printer::Sub("deps", write_deps).WithSuffix(",")}}, R"cc( static _upb_DefPool_Init *deps[$dep_count$] = { $deps$, NULL, }; )cc"); ctx.Emit("\n"); } void WriteDefPoolInitStruct(upb::FileDefPtr file, Context& ctx) { ctx.Emit( { {"defpool_init_name", ReflectionFileSymbol(file.name())}, {"file_name", file.name()}, {"mini_table_file_var_name", MiniTableFileVarName(file.name())}, }, R"cc( _upb_DefPool_Init $defpool_init_name$ = { deps, &$mini_table_file_var_name$, "$file_name$", UPB_STRINGVIEW_INIT(descriptor, sizeof(descriptor)), }; )cc"); } void WriteDefPoolInit(upb::FileDefPtr file, Context& ctx) { WriteDefPoolFwdDecls(file, ctx); WriteDescriptor(file, ctx); WriteDependencies(file, ctx); WriteDefPoolInitStruct(file, ctx); } void WriteDefSource(upb::FileDefPtr file, Context& ctx) { ctx.Emit( { {Sub("file_warning", FileWarning(file.name())).WithSuffix(";")}, {Sub("includes", [&] { WriteIncludes(file, ctx); }).WithSuffix(";")}, {Sub("def_pool_init", [&] { WriteDefPoolInit(file, ctx); }) .WithSuffix(";")}, }, R"cc( $file_warning$; $includes$; $def_pool_init$; )cc"); } } // namespace void GenerateReflectionSource(upb::FileDefPtr file, const Options& options, google::protobuf::compiler::GeneratorContext* context) { Context c_context(options, context->Open(DefSourceFilename(file))); WriteDefSource(file, c_context); } } // namespace upb::generator::reflection