• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include <algorithm>
9 #include <cassert>
10 #include <cmath>
11 #include <cstddef>
12 #include <cstdint>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <limits>
16 #include <map>
17 #include <string>
18 #include <utility>
19 #include <vector>
20 
21 #include "absl/base/macros.h"
22 #include "absl/log/absl_check.h"
23 #include "absl/log/absl_log.h"
24 #include "absl/strings/escaping.h"
25 #include "absl/strings/match.h"
26 #include "absl/strings/numbers.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/str_replace.h"
29 #include "absl/strings/string_view.h"
30 #include "absl/strings/substitute.h"
31 #include "upb/base/descriptor_constants.h"
32 #include "upb/base/status.hpp"
33 #include "upb/base/string_view.h"
34 #include "upb/mini_table/field.h"
35 #include "upb/reflection/def.hpp"
36 #include "upb_generator/c/names.h"
37 #include "upb_generator/c/names_internal.h"
38 #include "upb_generator/common.h"
39 #include "upb_generator/common/names.h"
40 #include "upb_generator/file_layout.h"
41 #include "upb_generator/minitable/names.h"
42 #include "upb_generator/minitable/names_internal.h"
43 #include "upb_generator/plugin.h"
44 
45 // Must be last.
46 #include "upb/port/def.inc"
47 
48 namespace upb {
49 namespace generator {
50 namespace {
51 
52 struct Options {
53   int bootstrap_stage = -1;  // -1 means not bootstrapped.
54   bool strip_nonfunctional_codegen = false;
55 };
56 
57 // Local convenience aliases for the public names.h header files.
58 
ExtensionIdentBase(upb::FieldDefPtr field)59 std::string ExtensionIdentBase(upb::FieldDefPtr field) {
60   return CApiExtensionIdentBase(field.full_name());
61 }
62 
MessageType(upb::MessageDefPtr descriptor)63 std::string MessageType(upb::MessageDefPtr descriptor) {
64   return CApiMessageType(descriptor.full_name());
65 }
66 
EnumType(upb::EnumDefPtr descriptor)67 std::string EnumType(upb::EnumDefPtr descriptor) {
68   return CApiEnumType(descriptor.full_name());
69 }
70 
EnumValueSymbol(upb::EnumValDefPtr value)71 std::string EnumValueSymbol(upb::EnumValDefPtr value) {
72   return CApiEnumValueSymbol(value.full_name());
73 }
74 
SourceFilename(upb::FileDefPtr file)75 std::string SourceFilename(upb::FileDefPtr file) {
76   return StripExtension(file.name()) + ".upb.c";
77 }
78 
MessageMiniTableRef(upb::MessageDefPtr descriptor,const Options & options)79 std::string MessageMiniTableRef(upb::MessageDefPtr descriptor,
80                                 const Options& options) {
81   if (options.bootstrap_stage == 0) {
82     return absl::StrCat(MiniTableMessageVarName(descriptor.full_name()), "()");
83   } else {
84     return absl::StrCat("&", MiniTableMessageVarName(descriptor.full_name()));
85   }
86 }
87 
EnumMiniTableRef(upb::EnumDefPtr descriptor,const Options & options)88 std::string EnumMiniTableRef(upb::EnumDefPtr descriptor,
89                              const Options& options) {
90   if (options.bootstrap_stage == 0) {
91     return absl::StrCat(MiniTableEnumVarName(descriptor.full_name()), "()");
92   } else {
93     return absl::StrCat("&", MiniTableEnumVarName(descriptor.full_name()));
94   }
95 }
96 
CTypeInternal(upb::FieldDefPtr field,bool is_const)97 std::string CTypeInternal(upb::FieldDefPtr field, bool is_const) {
98   std::string maybe_const = is_const ? "const " : "";
99   switch (field.ctype()) {
100     case kUpb_CType_Message: {
101       std::string maybe_struct =
102           field.file() != field.message_type().file() ? "struct " : "";
103       return maybe_const + maybe_struct + MessageType(field.message_type()) +
104              "*";
105     }
106     case kUpb_CType_Bool:
107       return "bool";
108     case kUpb_CType_Float:
109       return "float";
110     case kUpb_CType_Int32:
111     case kUpb_CType_Enum:
112       return "int32_t";
113     case kUpb_CType_UInt32:
114       return "uint32_t";
115     case kUpb_CType_Double:
116       return "double";
117     case kUpb_CType_Int64:
118       return "int64_t";
119     case kUpb_CType_UInt64:
120       return "uint64_t";
121     case kUpb_CType_String:
122     case kUpb_CType_Bytes:
123       return "upb_StringView";
124     default:
125       abort();
126   }
127 }
128 
FloatToCLiteral(float value)129 std::string FloatToCLiteral(float value) {
130   if (value == std::numeric_limits<float>::infinity()) {
131     return "kUpb_FltInfinity";
132   } else if (value == -std::numeric_limits<float>::infinity()) {
133     return "-kUpb_FltInfinity";
134   } else if (std::isnan(value)) {
135     return "kUpb_NaN";
136   } else {
137     return absl::StrCat(value);
138   }
139 }
140 
DoubleToCLiteral(double value)141 std::string DoubleToCLiteral(double value) {
142   if (value == std::numeric_limits<double>::infinity()) {
143     return "kUpb_Infinity";
144   } else if (value == -std::numeric_limits<double>::infinity()) {
145     return "-kUpb_Infinity";
146   } else if (std::isnan(value)) {
147     return "kUpb_NaN";
148   } else {
149     return absl::StrCat(value);
150   }
151 }
152 
153 // Escape trigraphs by escaping question marks to \?
EscapeTrigraphs(absl::string_view to_escape)154 std::string EscapeTrigraphs(absl::string_view to_escape) {
155   return absl::StrReplaceAll(to_escape, {{"?", "\\?"}});
156 }
157 
FieldDefault(upb::FieldDefPtr field)158 std::string FieldDefault(upb::FieldDefPtr field) {
159   switch (field.ctype()) {
160     case kUpb_CType_Message:
161       return "NULL";
162     case kUpb_CType_Bytes:
163     case kUpb_CType_String: {
164       upb_StringView str = field.default_value().str_val;
165       return absl::Substitute("upb_StringView_FromString(\"$0\")",
166                               EscapeTrigraphs(absl::CEscape(
167                                   absl::string_view(str.data, str.size))));
168     }
169     case kUpb_CType_Int32:
170       return absl::Substitute("(int32_t)$0", field.default_value().int32_val);
171     case kUpb_CType_Int64:
172       if (field.default_value().int64_val == INT64_MIN) {
173         // Special-case to avoid:
174         //   integer literal is too large to be represented in a signed integer
175         //   type, interpreting as unsigned
176         //   [-Werror,-Wimplicitly-unsigned-literal]
177         //   int64_t default_val = (int64_t)-9223372036854775808ll;
178         //
179         // More info here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661
180         return "INT64_MIN";
181       } else {
182         return absl::Substitute("(int64_t)$0ll",
183                                 field.default_value().int64_val);
184       }
185     case kUpb_CType_UInt32:
186       return absl::Substitute("(uint32_t)$0u",
187                               field.default_value().uint32_val);
188     case kUpb_CType_UInt64:
189       return absl::Substitute("(uint64_t)$0ull",
190                               field.default_value().uint64_val);
191     case kUpb_CType_Float:
192       return FloatToCLiteral(field.default_value().float_val);
193     case kUpb_CType_Double:
194       return DoubleToCLiteral(field.default_value().double_val);
195     case kUpb_CType_Bool:
196       return field.default_value().bool_val ? "true" : "false";
197     case kUpb_CType_Enum:
198       // Use a number instead of a symbolic name so that we don't require
199       // this enum's header to be included.
200       return absl::StrCat(field.default_value().int32_val);
201   }
202   ABSL_ASSERT(false);
203   return "XXX";
204 }
205 
CType(upb::FieldDefPtr field)206 std::string CType(upb::FieldDefPtr field) {
207   return CTypeInternal(field, false);
208 }
209 
CTypeConst(upb::FieldDefPtr field)210 std::string CTypeConst(upb::FieldDefPtr field) {
211   return CTypeInternal(field, true);
212 }
213 
MapKeyCType(upb::FieldDefPtr map_field)214 std::string MapKeyCType(upb::FieldDefPtr map_field) {
215   return CType(map_field.message_type().map_key());
216 }
217 
MapValueCType(upb::FieldDefPtr map_field)218 std::string MapValueCType(upb::FieldDefPtr map_field) {
219   return CType(map_field.message_type().map_value());
220 }
221 
MapKeyValueSize(upb_CType ctype,absl::string_view expr)222 std::string MapKeyValueSize(upb_CType ctype, absl::string_view expr) {
223   return ctype == kUpb_CType_String || ctype == kUpb_CType_Bytes
224              ? "0"
225              : absl::StrCat("sizeof(", expr, ")");
226 }
227 
MapKeySize(upb::FieldDefPtr map_field,absl::string_view expr)228 std::string MapKeySize(upb::FieldDefPtr map_field, absl::string_view expr) {
229   const upb_CType ctype = map_field.message_type().map_key().ctype();
230   return MapKeyValueSize(ctype, expr);
231 }
232 
MapValueSize(upb::FieldDefPtr map_field,absl::string_view expr)233 std::string MapValueSize(upb::FieldDefPtr map_field, absl::string_view expr) {
234   const upb_CType ctype = map_field.message_type().map_value().ctype();
235   return MapKeyValueSize(ctype, expr);
236 }
237 
238 std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field,
239                              const Options& options);
240 std::string FieldInitializerStrong(const DefPoolPair& pools,
241                                    upb::FieldDefPtr field,
242                                    const Options& options);
243 
DumpEnumValues(upb::EnumDefPtr desc,Output & output)244 void DumpEnumValues(upb::EnumDefPtr desc, Output& output) {
245   std::vector<upb::EnumValDefPtr> values;
246   values.reserve(desc.value_count());
247   for (int i = 0; i < desc.value_count(); i++) {
248     values.push_back(desc.value(i));
249   }
250   std::stable_sort(values.begin(), values.end(),
251                    [](upb::EnumValDefPtr a, upb::EnumValDefPtr b) {
252                      return a.number() < b.number();
253                    });
254 
255   for (size_t i = 0; i < values.size(); i++) {
256     auto value = values[i];
257     output("  $0 = $1", EnumValueSymbol(value), value.number());
258     if (i != values.size() - 1) {
259       output(",");
260     }
261     output("\n");
262   }
263 }
264 
GetFieldRep(const DefPoolPair & pools,upb::FieldDefPtr field)265 std::string GetFieldRep(const DefPoolPair& pools, upb::FieldDefPtr field) {
266   return upb::generator::GetFieldRep(pools.GetField32(field),
267                                      pools.GetField64(field));
268 }
269 
GenerateExtensionInHeader(const DefPoolPair & pools,upb::FieldDefPtr ext,const Options & options,Output & output)270 void GenerateExtensionInHeader(const DefPoolPair& pools, upb::FieldDefPtr ext,
271                                const Options& options, Output& output) {
272   output(
273       R"cc(
274         UPB_INLINE bool $0_has_$1(const struct $2* msg) {
275           return upb_Message_HasExtension((upb_Message*)msg, &$3);
276         }
277       )cc",
278       ExtensionIdentBase(ext), ext.name(), MessageType(ext.containing_type()),
279       MiniTableExtensionVarName(ext.full_name()));
280 
281   output(
282       R"cc(
283         UPB_INLINE void $0_clear_$1(struct $2* msg) {
284           upb_Message_ClearExtension((upb_Message*)msg, &$3);
285         }
286       )cc",
287       ExtensionIdentBase(ext), ext.name(), MessageType(ext.containing_type()),
288       MiniTableExtensionVarName(ext.full_name()));
289 
290   if (ext.IsSequence()) {
291     // TODO: We need generated accessors for repeated extensions.
292   } else {
293     output(
294         R"cc(
295           UPB_INLINE $0 $1_$2(const struct $3* msg) {
296             const upb_MiniTableExtension* ext = &$4;
297             UPB_ASSUME(upb_MiniTableField_IsScalar(&ext->UPB_PRIVATE(field)));
298             UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(
299                            &ext->UPB_PRIVATE(field)) == $5);
300             $0 default_val = $6;
301             $0 ret;
302             _upb_Message_GetExtensionField((upb_Message*)msg, ext, &default_val, &ret);
303             return ret;
304           }
305         )cc",
306         CTypeConst(ext), ExtensionIdentBase(ext), ext.name(),
307         MessageType(ext.containing_type()),
308         MiniTableExtensionVarName(ext.full_name()), GetFieldRep(pools, ext),
309         FieldDefault(ext));
310     output(
311         R"cc(
312           UPB_INLINE void $1_set_$2(struct $3* msg, $0 val, upb_Arena* arena) {
313             const upb_MiniTableExtension* ext = &$4;
314             UPB_ASSUME(upb_MiniTableField_IsScalar(&ext->UPB_PRIVATE(field)));
315             UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(
316                            &ext->UPB_PRIVATE(field)) == $5);
317             bool ok = upb_Message_SetExtension((upb_Message*)msg, ext, &val, arena);
318             UPB_ASSERT(ok);
319           }
320         )cc",
321         CTypeConst(ext), ExtensionIdentBase(ext), ext.name(),
322         MessageType(ext.containing_type()),
323         MiniTableExtensionVarName(ext.full_name()), GetFieldRep(pools, ext));
324 
325     // Message extensions also have a Msg_mutable_foo() accessor that will
326     // create the sub-message if it doesn't already exist.
327     if (ext.IsSubMessage()) {
328       output(
329           R"cc(
330             UPB_INLINE struct $0* $1_mutable_$2(struct $3* msg,
331                                                 upb_Arena* arena) {
332               struct $0* sub = (struct $0*)$1_$2(msg);
333               if (sub == NULL) {
334                 sub = (struct $0*)_upb_Message_New($4, arena);
335                 if (sub) $1_set_$2(msg, sub, arena);
336               }
337               return sub;
338             }
339           )cc",
340           MessageType(ext.message_type()), ExtensionIdentBase(ext), ext.name(),
341           MessageType(ext.containing_type()),
342           MessageMiniTableRef(ext.message_type(), options));
343     }
344   }
345 }
346 
GenerateMessageFunctionsInHeader(upb::MessageDefPtr message,const Options & options,Output & output)347 void GenerateMessageFunctionsInHeader(upb::MessageDefPtr message,
348                                       const Options& options, Output& output) {
349   // TODO: The generated code here does not check the return values
350   // from upb_Encode(). How can we even fix this without breaking other things?
351   output(
352       R"cc(
353         UPB_INLINE $0* $0_new(upb_Arena* arena) {
354           return ($0*)_upb_Message_New($1, arena);
355         }
356         UPB_INLINE $0* $0_parse(const char* buf, size_t size, upb_Arena* arena) {
357           $0* ret = $0_new(arena);
358           if (!ret) return NULL;
359           if (upb_Decode(buf, size, UPB_UPCAST(ret), $1, NULL, 0, arena) !=
360               kUpb_DecodeStatus_Ok) {
361             return NULL;
362           }
363           return ret;
364         }
365         UPB_INLINE $0* $0_parse_ex(const char* buf, size_t size,
366                                    const upb_ExtensionRegistry* extreg,
367                                    int options, upb_Arena* arena) {
368           $0* ret = $0_new(arena);
369           if (!ret) return NULL;
370           if (upb_Decode(buf, size, UPB_UPCAST(ret), $1, extreg, options,
371                          arena) != kUpb_DecodeStatus_Ok) {
372             return NULL;
373           }
374           return ret;
375         }
376         UPB_INLINE char* $0_serialize(const $0* msg, upb_Arena* arena, size_t* len) {
377           char* ptr;
378           (void)upb_Encode(UPB_UPCAST(msg), $1, 0, arena, &ptr, len);
379           return ptr;
380         }
381         UPB_INLINE char* $0_serialize_ex(const $0* msg, int options,
382                                          upb_Arena* arena, size_t* len) {
383           char* ptr;
384           (void)upb_Encode(UPB_UPCAST(msg), $1, options, arena, &ptr, len);
385           return ptr;
386         }
387       )cc",
388       MessageType(message), MessageMiniTableRef(message, options));
389 }
390 
GenerateOneofInHeader(upb::OneofDefPtr oneof,const DefPoolPair & pools,absl::string_view msg_name,const Options & options,Output & output)391 void GenerateOneofInHeader(upb::OneofDefPtr oneof, const DefPoolPair& pools,
392                            absl::string_view msg_name, const Options& options,
393                            Output& output) {
394   std::string fullname = CApiOneofIdentBase(oneof.full_name());
395   output("typedef enum {\n");
396   for (int j = 0; j < oneof.field_count(); j++) {
397     upb::FieldDefPtr field = oneof.field(j);
398     output("  $0_$1 = $2,\n", fullname, field.name(), field.number());
399   }
400   output(
401       "  $0_NOT_SET = 0\n"
402       "} $0_oneofcases;\n",
403       fullname);
404   output(
405       R"cc(
406         UPB_INLINE $0_oneofcases $1_$2_case(const $1* msg) {
407           const upb_MiniTableField field = $3;
408           return ($0_oneofcases)upb_Message_WhichOneofFieldNumber(
409               UPB_UPCAST(msg), &field);
410         }
411       )cc",
412       fullname, msg_name, oneof.name(),
413       FieldInitializer(pools, oneof.field(0), options));
414 }
415 
GenerateHazzer(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)416 void GenerateHazzer(upb::FieldDefPtr field, const DefPoolPair& pools,
417                     absl::string_view msg_name, const NameMangler& mangler,
418                     const Options& options, Output& output) {
419   std::string resolved_name = mangler.ResolveFieldName(field.name());
420   if (field.has_presence()) {
421     output(
422         R"cc(
423           UPB_INLINE bool $0_has_$1(const $0* msg) {
424             const upb_MiniTableField field = $2;
425             return upb_Message_HasBaseField(UPB_UPCAST(msg), &field);
426           }
427         )cc",
428         msg_name, resolved_name, FieldInitializer(pools, field, options));
429   }
430 }
431 
GenerateClear(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)432 void GenerateClear(upb::FieldDefPtr field, const DefPoolPair& pools,
433                    absl::string_view msg_name, const NameMangler& mangler,
434                    const Options& options, Output& output) {
435   if (field == field.containing_type().map_key() ||
436       field == field.containing_type().map_value()) {
437     // Cannot be cleared.
438     return;
439   }
440   std::string resolved_name = mangler.ResolveFieldName(field.name());
441   output(
442       R"cc(
443         UPB_INLINE void $0_clear_$1($0* msg) {
444           const upb_MiniTableField field = $2;
445           upb_Message_ClearBaseField(UPB_UPCAST(msg), &field);
446         }
447       )cc",
448       msg_name, resolved_name, FieldInitializer(pools, field, options));
449 }
450 
GenerateMapGetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)451 void GenerateMapGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
452                         absl::string_view msg_name, const NameMangler& mangler,
453                         const Options& options, Output& output) {
454   std::string resolved_name = mangler.ResolveFieldName(field.name());
455   output(
456       R"cc(
457         UPB_INLINE size_t $0_$1_size(const $0* msg) {
458           const upb_MiniTableField field = $2;
459           const upb_Map* map = upb_Message_GetMap(UPB_UPCAST(msg), &field);
460           return map ? _upb_Map_Size(map) : 0;
461         }
462       )cc",
463       msg_name, resolved_name, FieldInitializer(pools, field, options));
464   output(
465       R"cc(
466         UPB_INLINE bool $0_$1_get(const $0* msg, $2 key, $3* val) {
467           const upb_MiniTableField field = $4;
468           const upb_Map* map = upb_Message_GetMap(UPB_UPCAST(msg), &field);
469           if (!map) return false;
470           return _upb_Map_Get(map, &key, $5, val, $6);
471         }
472       )cc",
473       msg_name, resolved_name, MapKeyCType(field), MapValueCType(field),
474       FieldInitializerStrong(pools, field, options), MapKeySize(field, "key"),
475       MapValueSize(field, "*val"));
476   output(
477       R"cc(
478         UPB_INLINE $0 $1_$2_next(const $1* msg, size_t* iter) {
479           const upb_MiniTableField field = $3;
480           const upb_Map* map = upb_Message_GetMap(UPB_UPCAST(msg), &field);
481           if (!map) return NULL;
482           return ($0)_upb_map_next(map, iter);
483         }
484       )cc",
485       CTypeConst(field), msg_name, resolved_name,
486       FieldInitializerStrong(pools, field, options));
487   // Generate private getter returning a upb_Map or NULL for immutable and
488   // a upb_Map for mutable.
489   //
490   // Example:
491   //   UPB_INLINE const upb_Map* _name_immutable_upb_map(Foo* msg)
492   //   UPB_INLINE upb_Map* _name_mutable_upb_map(Foo* msg, upb_Arena* a)
493   output(
494       R"cc(
495         UPB_INLINE const upb_Map* _$0_$1_$2($0* msg) {
496           const upb_MiniTableField field = $4;
497           return upb_Message_GetMap(UPB_UPCAST(msg), &field);
498         }
499         UPB_INLINE upb_Map* _$0_$1_$3($0* msg, upb_Arena* a) {
500           const upb_MiniTableField field = $4;
501           return _upb_Message_GetOrCreateMutableMap(UPB_UPCAST(msg), &field, $5, $6, a);
502         }
503       )cc",
504       msg_name, resolved_name, kMapGetterPostfix, kMutableMapGetterPostfix,
505       FieldInitializerStrong(pools, field, options),
506       MapKeySize(field, MapKeyCType(field)),
507       MapValueSize(field, MapValueCType(field)));
508 }
509 
GenerateMapEntryGetters(upb::FieldDefPtr field,absl::string_view msg_name,Output & output)510 void GenerateMapEntryGetters(upb::FieldDefPtr field, absl::string_view msg_name,
511                              Output& output) {
512   output(
513       R"cc(
514         UPB_INLINE $0 $1_$2(const $1* msg) {
515           $3 ret;
516           _upb_msg_map_$2(msg, &ret, $4);
517           return ret;
518         }
519       )cc",
520       CTypeConst(field), msg_name, field.name(), CType(field),
521       field.ctype() == kUpb_CType_String ? "0" : "sizeof(ret)");
522 }
523 
GenerateRepeatedGetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)524 void GenerateRepeatedGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
525                              absl::string_view msg_name,
526                              const NameMangler& mangler, const Options& options,
527                              Output& output) {
528   // Generate getter returning first item and size.
529   //
530   // Example:
531   //   UPB_INLINE const struct Bar* const* name(const Foo* msg, size_t* size)
532   output(
533       R"cc(
534         UPB_INLINE $0 const* $1_$2(const $1* msg, size_t* size) {
535           const upb_MiniTableField field = $3;
536           const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field);
537           if (arr) {
538             if (size) *size = arr->UPB_PRIVATE(size);
539             return ($0 const*)upb_Array_DataPtr(arr);
540           } else {
541             if (size) *size = 0;
542             return NULL;
543           }
544         }
545       )cc",
546       CTypeConst(field),                             // $0
547       msg_name,                                      // $1
548       mangler.ResolveFieldName(field.name()),        // $2
549       FieldInitializerStrong(pools, field, options)  // #3
550   );
551   // Generate private getter returning array or NULL for immutable and upb_Array
552   // for mutable.
553   //
554   // Example:
555   //   UPB_INLINE const upb_Array* _name_upbarray(size_t* size)
556   //   UPB_INLINE upb_Array* _name_mutable_upbarray(size_t* size)
557   output(
558       R"cc(
559         UPB_INLINE const upb_Array* _$1_$2_$4(const $1* msg, size_t* size) {
560           const upb_MiniTableField field = $3;
561           const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field);
562           if (size) {
563             *size = arr ? arr->UPB_PRIVATE(size) : 0;
564           }
565           return arr;
566         }
567         UPB_INLINE upb_Array* _$1_$2_$5($1* msg, size_t* size, upb_Arena* arena) {
568           const upb_MiniTableField field = $3;
569           upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg),
570                                                                &field, arena);
571           if (size) {
572             *size = arr ? arr->UPB_PRIVATE(size) : 0;
573           }
574           return arr;
575         }
576       )cc",
577       CTypeConst(field),                              // $0
578       msg_name,                                       // $1
579       mangler.ResolveFieldName(field.name()),         // $2
580       FieldInitializerStrong(pools, field, options),  // $3
581       kRepeatedFieldArrayGetterPostfix,               // $4
582       kRepeatedFieldMutableArrayGetterPostfix         // $5
583   );
584 }
585 
GenerateScalarGetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & Options,Output & output)586 void GenerateScalarGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
587                            absl::string_view msg_name,
588                            const NameMangler& mangler, const Options& Options,
589                            Output& output) {
590   std::string field_name = mangler.ResolveFieldName(field.name());
591   output(
592       R"cc(
593         UPB_INLINE $0 $1_$2(const $1* msg) {
594           $0 default_val = $3;
595           $0 ret;
596           const upb_MiniTableField field = $4;
597           _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field,
598                                             &default_val, &ret);
599           return ret;
600         }
601       )cc",
602       CTypeConst(field), msg_name, field_name, FieldDefault(field),
603       FieldInitializerStrong(pools, field, Options));
604 }
605 
GenerateGetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)606 void GenerateGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
607                      absl::string_view msg_name, const NameMangler& mangler,
608                      const Options& options, Output& output) {
609   if (field.IsMap()) {
610     GenerateMapGetters(field, pools, msg_name, mangler, options, output);
611   } else if (field.containing_type().mapentry()) {
612     GenerateMapEntryGetters(field, msg_name, output);
613   } else if (field.IsSequence()) {
614     GenerateRepeatedGetters(field, pools, msg_name, mangler, options, output);
615   } else {
616     GenerateScalarGetters(field, pools, msg_name, mangler, options, output);
617   }
618 }
619 
GenerateMapSetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)620 void GenerateMapSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
621                         absl::string_view msg_name, const NameMangler& mangler,
622                         const Options& options, Output& output) {
623   std::string resolved_name = mangler.ResolveFieldName(field.name());
624   output(
625       R"cc(
626         UPB_INLINE void $0_$1_clear($0* msg) {
627           const upb_MiniTableField field = $2;
628           upb_Map* map = (upb_Map*)upb_Message_GetMap(UPB_UPCAST(msg), &field);
629           if (!map) return;
630           _upb_Map_Clear(map);
631         }
632       )cc",
633       msg_name, resolved_name, FieldInitializer(pools, field, options));
634   output(
635       R"cc(
636         UPB_INLINE bool $0_$1_set($0* msg, $2 key, $3 val, upb_Arena* a) {
637           const upb_MiniTableField field = $4;
638           upb_Map* map = _upb_Message_GetOrCreateMutableMap(UPB_UPCAST(msg),
639                                                             &field, $5, $6, a);
640           return _upb_Map_Insert(map, &key, $5, &val, $6, a) !=
641                  kUpb_MapInsertStatus_OutOfMemory;
642         }
643       )cc",
644       msg_name, resolved_name, MapKeyCType(field), MapValueCType(field),
645       FieldInitializerStrong(pools, field, options), MapKeySize(field, "key"),
646       MapValueSize(field, "val"));
647   output(
648       R"cc(
649         UPB_INLINE bool $0_$1_delete($0* msg, $2 key) {
650           const upb_MiniTableField field = $3;
651           upb_Map* map = (upb_Map*)upb_Message_GetMap(UPB_UPCAST(msg), &field);
652           if (!map) return false;
653           return _upb_Map_Delete(map, &key, $4, NULL);
654         }
655       )cc",
656       msg_name, resolved_name, MapKeyCType(field),
657       FieldInitializer(pools, field, options), MapKeySize(field, "key"));
658   output(
659       R"cc(
660         UPB_INLINE $0 $1_$2_nextmutable($1* msg, size_t* iter) {
661           const upb_MiniTableField field = $3;
662           upb_Map* map = (upb_Map*)upb_Message_GetMap(UPB_UPCAST(msg), &field);
663           if (!map) return NULL;
664           return ($0)_upb_map_next(map, iter);
665         }
666       )cc",
667       CType(field), msg_name, resolved_name,
668       FieldInitializerStrong(pools, field, options));
669 }
670 
GenerateRepeatedSetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)671 void GenerateRepeatedSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
672                              absl::string_view msg_name,
673                              const NameMangler& mangler, const Options& options,
674                              Output& output) {
675   std::string resolved_name = mangler.ResolveFieldName(field.name());
676   output(
677       R"cc(
678         UPB_INLINE $0* $1_mutable_$2($1* msg, size_t* size) {
679           upb_MiniTableField field = $3;
680           upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field);
681           if (arr) {
682             if (size) *size = arr->UPB_PRIVATE(size);
683             return ($0*)upb_Array_MutableDataPtr(arr);
684           } else {
685             if (size) *size = 0;
686             return NULL;
687           }
688         }
689       )cc",
690       CType(field), msg_name, resolved_name,
691       FieldInitializerStrong(pools, field, options));
692   output(
693       R"cc(
694         UPB_INLINE $0* $1_resize_$2($1* msg, size_t size, upb_Arena* arena) {
695           upb_MiniTableField field = $3;
696           return ($0*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg),
697                                                            &field, size, arena);
698         }
699       )cc",
700       CType(field), msg_name, resolved_name,
701       FieldInitializer(pools, field, options));
702   if (field.ctype() == kUpb_CType_Message) {
703     output(
704         R"cc(
705           UPB_INLINE struct $0* $1_add_$2($1* msg, upb_Arena* arena) {
706             upb_MiniTableField field = $4;
707             upb_Array* arr = upb_Message_GetOrCreateMutableArray(
708                 UPB_UPCAST(msg), &field, arena);
709             if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(
710                             arr, arr->UPB_PRIVATE(size) + 1, arena)) {
711               return NULL;
712             }
713             struct $0* sub = (struct $0*)_upb_Message_New($3, arena);
714             if (!arr || !sub) return NULL;
715             UPB_PRIVATE(_upb_Array_Set)
716             (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub));
717             return sub;
718           }
719         )cc",
720         MessageType(field.message_type()), msg_name, resolved_name,
721         MessageMiniTableRef(field.message_type(), options),
722         FieldInitializerStrong(pools, field, options));
723   } else {
724     output(
725         R"cc(
726           UPB_INLINE bool $1_add_$2($1* msg, $0 val, upb_Arena* arena) {
727             upb_MiniTableField field = $3;
728             upb_Array* arr = upb_Message_GetOrCreateMutableArray(
729                 UPB_UPCAST(msg), &field, arena);
730             if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(
731                             arr, arr->UPB_PRIVATE(size) + 1, arena)) {
732               return false;
733             }
734             UPB_PRIVATE(_upb_Array_Set)
735             (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val));
736             return true;
737           }
738         )cc",
739         CType(field), msg_name, resolved_name,
740         FieldInitializerStrong(pools, field, options));
741   }
742 }
743 
GenerateNonRepeatedSetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)744 void GenerateNonRepeatedSetters(upb::FieldDefPtr field,
745                                 const DefPoolPair& pools,
746                                 absl::string_view msg_name,
747                                 const NameMangler& mangler,
748                                 const Options& options, Output& output) {
749   if (field == field.containing_type().map_key()) {
750     // Key cannot be mutated.
751     return;
752   }
753 
754   std::string field_name = mangler.ResolveFieldName(field.name());
755 
756   if (field == field.containing_type().map_value()) {
757     output(R"cc(
758              UPB_INLINE void $0_set_$1($0 *msg, $2 value) {
759                _upb_msg_map_set_value(msg, &value, $3);
760              }
761            )cc",
762            msg_name, field_name, CType(field),
763            field.ctype() == kUpb_CType_String ? "0"
764                                               : "sizeof(" + CType(field) + ")");
765   } else {
766     output(R"cc(
767              UPB_INLINE void $0_set_$1($0 *msg, $2 value) {
768                const upb_MiniTableField field = $3;
769                upb_Message_SetBaseField((upb_Message *)msg, &field, &value);
770              }
771            )cc",
772            msg_name, field_name, CType(field),
773            FieldInitializerStrong(pools, field, options));
774   }
775 
776   // Message fields also have a Msg_mutable_foo() accessor that will create
777   // the sub-message if it doesn't already exist.
778   if (field.IsSubMessage() && !field.containing_type().mapentry()) {
779     output(
780         R"cc(
781           UPB_INLINE struct $0* $1_mutable_$2($1* msg, upb_Arena* arena) {
782             struct $0* sub = (struct $0*)$1_$2(msg);
783             if (sub == NULL) {
784               sub = (struct $0*)_upb_Message_New($3, arena);
785               if (sub) $1_set_$2(msg, sub);
786             }
787             return sub;
788           }
789         )cc",
790         MessageType(field.message_type()), msg_name, field_name,
791         MessageMiniTableRef(field.message_type(), options));
792   }
793 }
794 
GenerateSetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameMangler & mangler,const Options & options,Output & output)795 void GenerateSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
796                      absl::string_view msg_name, const NameMangler& mangler,
797                      const Options& options, Output& output) {
798   if (field.IsMap()) {
799     GenerateMapSetters(field, pools, msg_name, mangler, options, output);
800   } else if (field.IsSequence()) {
801     GenerateRepeatedSetters(field, pools, msg_name, mangler, options, output);
802   } else {
803     GenerateNonRepeatedSetters(field, pools, msg_name, mangler, options,
804                                output);
805   }
806 }
807 
GenerateMessageInHeader(upb::MessageDefPtr message,const DefPoolPair & pools,const Options & options,Output & output)808 void GenerateMessageInHeader(upb::MessageDefPtr message,
809                              const DefPoolPair& pools, const Options& options,
810                              Output& output) {
811   output("/* $0 */\n\n", message.full_name());
812   std::string msg_name = MessageType(message);
813   if (!message.mapentry()) {
814     GenerateMessageFunctionsInHeader(message, options, output);
815   }
816 
817   for (int i = 0; i < message.real_oneof_count(); i++) {
818     GenerateOneofInHeader(message.oneof(i), pools, msg_name, options, output);
819   }
820 
821   NameMangler mangler(GetUpbFields(message));
822   for (auto field : FieldNumberOrder(message)) {
823     GenerateClear(field, pools, msg_name, mangler, options, output);
824     GenerateGetters(field, pools, msg_name, mangler, options, output);
825     GenerateHazzer(field, pools, msg_name, mangler, options, output);
826   }
827 
828   output("\n");
829 
830   for (auto field : FieldNumberOrder(message)) {
831     GenerateSetters(field, pools, msg_name, mangler, options, output);
832   }
833 
834   output("\n");
835 }
836 
SortedForwardMessages(const std::vector<upb::MessageDefPtr> & this_file_messages,const std::vector<upb::FieldDefPtr> & this_file_exts)837 std::vector<upb::MessageDefPtr> SortedForwardMessages(
838     const std::vector<upb::MessageDefPtr>& this_file_messages,
839     const std::vector<upb::FieldDefPtr>& this_file_exts) {
840   std::map<std::string, upb::MessageDefPtr> forward_messages;
841   for (auto message : this_file_messages) {
842     for (int i = 0; i < message.field_count(); i++) {
843       upb::FieldDefPtr field = message.field(i);
844       if (field.ctype() == kUpb_CType_Message &&
845           field.file() != field.message_type().file()) {
846         forward_messages[field.message_type().full_name()] =
847             field.message_type();
848       }
849     }
850   }
851   for (auto ext : this_file_exts) {
852     if (ext.file() != ext.containing_type().file()) {
853       forward_messages[ext.containing_type().full_name()] =
854           ext.containing_type();
855     }
856   }
857   std::vector<upb::MessageDefPtr> ret;
858   ret.reserve(forward_messages.size());
859   for (const auto& pair : forward_messages) {
860     ret.push_back(pair.second);
861   }
862   return ret;
863 }
864 
WriteHeader(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Output & output)865 void WriteHeader(const DefPoolPair& pools, upb::FileDefPtr file,
866                  const Options& options, Output& output) {
867   const std::vector<upb::MessageDefPtr> this_file_messages =
868       SortedMessages(file);
869   const std::vector<upb::FieldDefPtr> this_file_exts = SortedExtensions(file);
870   std::vector<upb::EnumDefPtr> this_file_enums = SortedEnums(file, kAllEnums);
871   std::vector<upb::MessageDefPtr> forward_messages =
872       SortedForwardMessages(this_file_messages, this_file_exts);
873 
874   output(FileWarning(file.name()));
875   output(
876       "#ifndef $0_UPB_H_\n"
877       "#define $0_UPB_H_\n\n"
878       "#include \"upb/generated_code_support.h\"\n\n",
879       IncludeGuard(file.name()));
880 
881   for (int i = 0; i < file.public_dependency_count(); i++) {
882     if (i == 0) {
883       output("/* Public Imports. */\n");
884     }
885     output("#include \"$0\"\n",
886            CApiHeaderFilename(file.public_dependency(i).name(),
887                               options.bootstrap_stage >= 0));
888   }
889   if (file.public_dependency_count() > 0) {
890     output("\n");
891   }
892 
893   if (options.bootstrap_stage != 0) {
894     output("#include \"$0\"\n\n",
895            MiniTableHeaderFilename(file.name(), options.bootstrap_stage >= 0));
896     for (int i = 0; i < file.dependency_count(); i++) {
897       if (options.strip_nonfunctional_codegen &&
898           google::protobuf::compiler::IsKnownFeatureProto(file.dependency(i).name())) {
899         // Strip feature imports for editions codegen tests.
900         continue;
901       }
902       output("#include \"$0\"\n",
903              MiniTableHeaderFilename(file.dependency(i).name(),
904                                      options.bootstrap_stage >= 0));
905     }
906     output("\n");
907   }
908 
909   output(
910       "// Must be last.\n"
911       "#include \"upb/port/def.inc\"\n"
912       "\n"
913       "#ifdef __cplusplus\n"
914       "extern \"C\" {\n"
915       "#endif\n"
916       "\n");
917 
918   if (options.bootstrap_stage == 0) {
919     for (auto message : this_file_messages) {
920       output("extern const upb_MiniTable* $0(void);\n",
921              MiniTableMessageVarName(message.full_name()));
922     }
923     for (auto message : forward_messages) {
924       output("extern const upb_MiniTable* $0(void);\n",
925              MiniTableMessageVarName(message.full_name()));
926     }
927     for (auto enumdesc : this_file_enums) {
928       output("extern const upb_MiniTableEnum* $0(void);\n",
929              MiniTableEnumVarName(enumdesc.full_name()));
930     }
931     output("\n");
932   }
933 
934   // Forward-declare types defined in this file.
935   for (auto message : this_file_messages) {
936     output("typedef struct $0 { upb_Message UPB_PRIVATE(base); } $0;\n",
937            MessageType(message));
938   }
939 
940   // Forward-declare types not in this file, but used as submessages.
941   // Order by full name for consistent ordering.
942   for (auto msg : forward_messages) {
943     output("struct $0;\n", MessageType(msg));
944   }
945 
946   if (!this_file_messages.empty()) {
947     output("\n");
948   }
949 
950   for (auto enumdesc : this_file_enums) {
951     output("typedef enum {\n");
952     DumpEnumValues(enumdesc, output);
953     output("} $0;\n\n", EnumType(enumdesc));
954   }
955 
956   output("\n");
957 
958   output("\n");
959   for (auto message : this_file_messages) {
960     GenerateMessageInHeader(message, pools, options, output);
961   }
962 
963   for (auto ext : this_file_exts) {
964     GenerateExtensionInHeader(pools, ext, options, output);
965   }
966 
967   if (absl::string_view(file.name()) == "google/protobuf/descriptor.proto" ||
968       absl::string_view(file.name()) == "net/proto2/proto/descriptor.proto") {
969     // This is gratuitously inefficient with how many times it rebuilds
970     // MessageLayout objects for the same message. But we only do this for one
971     // proto (descriptor.proto) so we don't worry about it.
972     upb::MessageDefPtr max32_message;
973     upb::MessageDefPtr max64_message;
974     size_t max32 = 0;
975     size_t max64 = 0;
976     for (const auto message : this_file_messages) {
977       if (absl::EndsWith(message.name(), "Options")) {
978         size_t size32 = pools.GetMiniTable32(message)->UPB_PRIVATE(size);
979         size_t size64 = pools.GetMiniTable64(message)->UPB_PRIVATE(size);
980         if (size32 > max32) {
981           max32 = size32;
982           max32_message = message;
983         }
984         if (size64 > max64) {
985           max64 = size64;
986           max64_message = message;
987         }
988       }
989     }
990 
991     output("/* Max size 32 is $0 */\n", max32_message.full_name());
992     output("/* Max size 64 is $0 */\n", max64_message.full_name());
993     output("#define _UPB_MAXOPT_SIZE UPB_SIZE($0, $1)\n\n", max32, max64);
994   }
995 
996   output(
997       "#ifdef __cplusplus\n"
998       "}  /* extern \"C\" */\n"
999       "#endif\n"
1000       "\n"
1001       "#include \"upb/port/undef.inc\"\n"
1002       "\n"
1003       "#endif  /* $0_UPB_H_ */\n",
1004       IncludeGuard(file.name()));
1005 }
1006 
FieldInitializer(upb::FieldDefPtr field,const upb_MiniTableField * field64,const upb_MiniTableField * field32,const Options & options)1007 std::string FieldInitializer(upb::FieldDefPtr field,
1008                              const upb_MiniTableField* field64,
1009                              const upb_MiniTableField* field32,
1010                              const Options& options) {
1011   if (options.bootstrap_stage == 0) {
1012     ABSL_CHECK(!field.is_extension());
1013     return absl::Substitute(
1014         "*upb_MiniTable_FindFieldByNumber($0, $1)",
1015         MessageMiniTableRef(field.containing_type(), options), field.number());
1016   } else {
1017     return upb::generator::FieldInitializer(field, field64, field32);
1018   }
1019 }
1020 
StrongReferenceSingle(upb::FieldDefPtr field)1021 std::string StrongReferenceSingle(upb::FieldDefPtr field) {
1022   if (!field.message_type()) return "";
1023   return absl::Substitute(
1024       "  UPB_PRIVATE(_upb_MiniTable_StrongReference)(&$0)",
1025       MiniTableMessageVarName(field.message_type().full_name()));
1026 }
1027 
StrongReference(upb::FieldDefPtr field)1028 std::string StrongReference(upb::FieldDefPtr field) {
1029   if (field.IsMap() &&
1030       field.message_type().FindFieldByNumber(2).IsSubMessage()) {
1031     return StrongReferenceSingle(field) + ";\n" +
1032            StrongReferenceSingle(field.message_type().FindFieldByNumber(2));
1033   } else {
1034     return StrongReferenceSingle(field);
1035   }
1036 }
FieldInitializerStrong(const DefPoolPair & pools,upb::FieldDefPtr field,const Options & options)1037 std::string FieldInitializerStrong(const DefPoolPair& pools,
1038                                    upb::FieldDefPtr field,
1039                                    const Options& options) {
1040   std::string ret = FieldInitializer(pools, field, options);
1041   if (options.bootstrap_stage != 0 && field.IsSubMessage()) {
1042     ret += ";\n" + StrongReference(field);
1043   }
1044   return ret;
1045 }
1046 
FieldInitializer(const DefPoolPair & pools,upb::FieldDefPtr field,const Options & options)1047 std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field,
1048                              const Options& options) {
1049   return FieldInitializer(field, pools.GetField64(field),
1050                           pools.GetField32(field), options);
1051 }
1052 
WriteMessageMiniDescriptorInitializer(upb::MessageDefPtr msg,const Options & options,Output & output)1053 void WriteMessageMiniDescriptorInitializer(upb::MessageDefPtr msg,
1054                                            const Options& options,
1055                                            Output& output) {
1056   Output resolve_calls;
1057   for (int i = 0; i < msg.field_count(); i++) {
1058     upb::FieldDefPtr field = msg.field(i);
1059     if (!field.message_type() && !field.enum_subdef()) continue;
1060     if (field.message_type()) {
1061       resolve_calls(
1062           "upb_MiniTable_SetSubMessage(mini_table, "
1063           "(upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, "
1064           "$0), $1);\n  ",
1065           field.number(), MessageMiniTableRef(field.message_type(), options));
1066     } else if (field.enum_subdef() && field.enum_subdef().is_closed()) {
1067       resolve_calls(
1068           "upb_MiniTable_SetSubEnum(mini_table, "
1069           "(upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, "
1070           "$0), $1);\n  ",
1071           field.number(), EnumMiniTableRef(field.enum_subdef(), options));
1072     }
1073   }
1074 
1075   output(
1076       R"cc(
1077         const upb_MiniTable* $0() {
1078           static upb_MiniTable* mini_table = NULL;
1079           static const char* mini_descriptor = "$1";
1080           if (mini_table) return mini_table;
1081           mini_table =
1082               upb_MiniTable_Build(mini_descriptor, strlen(mini_descriptor),
1083                                   upb_BootstrapArena(), NULL);
1084           $2return mini_table;
1085         }
1086       )cc",
1087       MiniTableMessageVarName(msg.full_name()), msg.MiniDescriptorEncode(),
1088       resolve_calls.output());
1089   output("\n");
1090 }
1091 
WriteEnumMiniDescriptorInitializer(upb::EnumDefPtr enum_def,const Options & options,Output & output)1092 void WriteEnumMiniDescriptorInitializer(upb::EnumDefPtr enum_def,
1093                                         const Options& options,
1094                                         Output& output) {
1095   output(
1096       R"cc(
1097         const upb_MiniTableEnum* $0() {
1098           static const upb_MiniTableEnum* mini_table = NULL;
1099           static const char* mini_descriptor = "$1";
1100           if (mini_table) return mini_table;
1101           mini_table =
1102               upb_MiniTableEnum_Build(mini_descriptor, strlen(mini_descriptor),
1103                                       upb_BootstrapArena(), NULL);
1104           return mini_table;
1105         }
1106       )cc",
1107       MiniTableEnumVarName(enum_def.full_name()),
1108       enum_def.MiniDescriptorEncode());
1109   output("\n");
1110 }
1111 
WriteMiniDescriptorSource(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Output & output)1112 void WriteMiniDescriptorSource(const DefPoolPair& pools, upb::FileDefPtr file,
1113                                const Options& options, Output& output) {
1114   output(
1115       "#include <stddef.h>\n"
1116       "#include \"upb/generated_code_support.h\"\n"
1117       "#include \"$0\"\n\n",
1118       CApiHeaderFilename(file.name(), options.bootstrap_stage >= 0));
1119 
1120   for (int i = 0; i < file.dependency_count(); i++) {
1121     if (options.strip_nonfunctional_codegen &&
1122         google::protobuf::compiler::IsKnownFeatureProto(file.dependency(i).name())) {
1123       continue;
1124     }
1125     output("#include \"$0\"\n",
1126            CApiHeaderFilename(file.dependency(i).name(),
1127                               options.bootstrap_stage >= 0));
1128   }
1129 
1130   output(
1131       R"cc(
1132         static upb_Arena* upb_BootstrapArena() {
1133           static upb_Arena* arena = NULL;
1134           if (!arena) arena = upb_Arena_New();
1135           return arena;
1136         }
1137       )cc");
1138 
1139   output("\n");
1140 
1141   for (const auto msg : SortedMessages(file)) {
1142     WriteMessageMiniDescriptorInitializer(msg, options, output);
1143   }
1144 
1145   for (const auto msg : SortedEnums(file, kClosedEnums)) {
1146     WriteEnumMiniDescriptorInitializer(msg, options, output);
1147   }
1148 }
1149 
GenerateFile(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Plugin * plugin)1150 void GenerateFile(const DefPoolPair& pools, upb::FileDefPtr file,
1151                   const Options& options, Plugin* plugin) {
1152   Output h_output;
1153   WriteHeader(pools, file, options, h_output);
1154   plugin->AddOutputFile(CApiHeaderFilename(file.name(), false),
1155                         h_output.output());
1156 
1157   if (options.bootstrap_stage == 0) {
1158     Output c_output;
1159     WriteMiniDescriptorSource(pools, file, options, c_output);
1160     plugin->AddOutputFile(SourceFilename(file), c_output.output());
1161   } else {
1162     // TODO: remove once we can figure out how to make both Blaze
1163     // and Bazel happy with header-only libraries.
1164 
1165     plugin->AddOutputFile(SourceFilename(file), "\n");
1166   }
1167 }
1168 
ParseOptions(Plugin * plugin,Options * options)1169 bool ParseOptions(Plugin* plugin, Options* options) {
1170   for (const auto& pair : ParseGeneratorParameter(plugin->parameter())) {
1171     if (pair.first == "bootstrap_stage") {
1172       if (!absl::SimpleAtoi(pair.second, &options->bootstrap_stage)) {
1173         plugin->SetError(absl::Substitute("Bad stage: $0", pair.second));
1174         return false;
1175       }
1176     } else if (pair.first == "experimental_strip_nonfunctional_codegen") {
1177       options->strip_nonfunctional_codegen = true;
1178     } else {
1179       plugin->SetError(absl::Substitute("Unknown parameter: $0", pair.first));
1180       return false;
1181     }
1182   }
1183 
1184   return true;
1185 }
1186 
ToStringView(upb_StringView str)1187 absl::string_view ToStringView(upb_StringView str) {
1188   return absl::string_view(str.data, str.size);
1189 }
1190 
1191 }  // namespace
1192 
1193 }  // namespace generator
1194 }  // namespace upb
1195 
main(int argc,char ** argv)1196 int main(int argc, char** argv) {
1197   upb::generator::DefPoolPair pools;
1198   upb::generator::Plugin plugin;
1199   upb::generator::Options options;
1200   if (!ParseOptions(&plugin, &options)) return 0;
1201   plugin.GenerateFilesRaw(
1202       [&](const UPB_DESC(FileDescriptorProto) * file_proto, bool generate) {
1203         upb::Status status;
1204         upb::FileDefPtr file = pools.AddFile(file_proto, &status);
1205         if (!file) {
1206           absl::string_view name = upb::generator::ToStringView(
1207               UPB_DESC(FileDescriptorProto_name)(file_proto));
1208           ABSL_LOG(FATAL) << "Couldn't add file " << name
1209                           << " to DefPool: " << status.error_message();
1210         }
1211         if (generate) GenerateFile(pools, file, options, &plugin);
1212       });
1213   return 0;
1214 }
1215