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