blob: 44a0cc64f78b47b39b4b71377bbaf8e697f7232f [file] [log] [blame]
Adam Cozzette501ecec2023-09-26 14:36:20 -07001// Protocol Buffers - Google's data interchange format
2// Copyright 2023 Google LLC. All rights reserved.
Adam Cozzette501ecec2023-09-26 14:36:20 -07003//
Hong Shinc482a8a2023-11-09 09:30:34 -08004// 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
Adam Cozzette501ecec2023-09-26 14:36:20 -07007
8#include "protos_generator/gen_accessors.h"
9
10#include <string>
11
12#include "absl/container/flat_hash_set.h"
13#include "absl/strings/match.h"
14#include "absl/strings/str_cat.h"
15#include "absl/strings/string_view.h"
16#include "google/protobuf/descriptor.h"
17#include "protos_generator/gen_repeated_fields.h"
18#include "protos_generator/gen_utils.h"
19#include "protos_generator/names.h"
20#include "protos_generator/output.h"
Adam Cozzette12c7bb02023-09-28 12:54:11 -070021#include "upb_generator/common.h"
22#include "upb_generator/keywords.h"
23#include "upb_generator/names.h"
Adam Cozzette501ecec2023-09-26 14:36:20 -070024
25namespace protos_generator {
26
27namespace protobuf = ::google::protobuf;
28
29using NameToFieldDescriptorMap =
30 absl::flat_hash_map<absl::string_view, const protobuf::FieldDescriptor*>;
31
32void WriteFieldAccessorHazzer(const protobuf::Descriptor* desc,
33 const protobuf::FieldDescriptor* field,
34 absl::string_view resolved_field_name,
35 absl::string_view resolved_upbc_name,
36 Output& output);
37void WriteFieldAccessorClear(const protobuf::Descriptor* desc,
38 const protobuf::FieldDescriptor* field,
39 absl::string_view resolved_field_name,
40 absl::string_view resolved_upbc_name,
41 Output& output);
42void WriteMapFieldAccessors(const protobuf::Descriptor* desc,
43 const protobuf::FieldDescriptor* field,
44 absl::string_view resolved_field_name,
45 absl::string_view resolved_upbc_name,
46 Output& output);
47
48void WriteMapAccessorDefinitions(const protobuf::Descriptor* message,
49 const protobuf::FieldDescriptor* field,
50 absl::string_view resolved_field_name,
51 absl::string_view class_name, Output& output);
52
53// Returns C++ class member name by resolving naming conflicts across
54// proto field names (such as clear_ prefixes) and keyword collisions.
55//
56// The Upb C generator prefixes all accessors with package and class names
57// avoiding collisions. Therefore we need to use raw field names when calling
58// into C accessors but need to fully resolve conflicts for C++ class members.
59std::string ResolveFieldName(const protobuf::FieldDescriptor* field,
60 const NameToFieldDescriptorMap& field_names);
61
62NameToFieldDescriptorMap CreateFieldNameMap(
63 const protobuf::Descriptor* message) {
64 NameToFieldDescriptorMap field_names;
65 for (int i = 0; i < message->field_count(); i++) {
66 const protobuf::FieldDescriptor* field = message->field(i);
67 field_names.emplace(field->name(), field);
68 }
69 return field_names;
70}
71
72void WriteFieldAccessorsInHeader(const protobuf::Descriptor* desc,
73 Output& output) {
74 // Generate const methods.
75 OutputIndenter i(output);
76
77 auto field_names = CreateFieldNameMap(desc);
Adam Cozzette12c7bb02023-09-28 12:54:11 -070078 auto upbc_field_names = upb::generator::CreateFieldNameMap(desc);
Adam Cozzette501ecec2023-09-26 14:36:20 -070079
80 for (const auto* field : FieldNumberOrder(desc)) {
81 std::string resolved_field_name = ResolveFieldName(field, field_names);
82 std::string resolved_upbc_name =
Adam Cozzette12c7bb02023-09-28 12:54:11 -070083 upb::generator::ResolveFieldName(field, upbc_field_names);
Adam Cozzette501ecec2023-09-26 14:36:20 -070084 WriteFieldAccessorHazzer(desc, field, resolved_field_name,
85 resolved_upbc_name, output);
86 WriteFieldAccessorClear(desc, field, resolved_field_name,
87 resolved_upbc_name, output);
88
89 if (field->is_map()) {
90 WriteMapFieldAccessors(desc, field, resolved_field_name,
91 resolved_upbc_name, output);
92 } else if (desc->options().map_entry()) {
93 // TODO Implement map entry
94 } else if (field->is_repeated()) {
95 WriteRepeatedFieldsInMessageHeader(desc, field, resolved_field_name,
96 resolved_upbc_name, output);
97 } else {
98 // non-repeated.
99 if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
100 output(R"cc(
101 $0 $1() const;
102 void set_$1($0 value);
103 )cc",
104 CppConstType(field), resolved_field_name);
105 } else if (field->cpp_type() ==
106 protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
107 output(R"cc(
108 $1 $2() const;
109 $0 mutable_$2();
110 )cc",
111 MessagePtrConstType(field, /* const */ false),
112 MessagePtrConstType(field, /* const */ true),
113 resolved_field_name, resolved_upbc_name);
114 } else {
115 output(
116 R"cc(
117 inline $0 $1() const { return $2_$3(msg_); }
118 inline void set_$1($0 value) { return $2_set_$3(msg_, value); }
119 )cc",
120 CppConstType(field), resolved_field_name, MessageName(desc),
121 resolved_upbc_name);
122 }
123 }
124 }
125}
126
127void WriteFieldAccessorHazzer(const protobuf::Descriptor* desc,
128 const protobuf::FieldDescriptor* field,
129 const absl::string_view resolved_field_name,
130 const absl::string_view resolved_upbc_name,
131 Output& output) {
132 // Generate hazzer (if any).
133 if (field->has_presence()) {
134 // Has presence.
135 output("inline bool has_$0() const { return $1_has_$2(msg_); }\n",
136 resolved_field_name, MessageName(desc), resolved_upbc_name);
137 }
138}
139
140void WriteFieldAccessorClear(const protobuf::Descriptor* desc,
141 const protobuf::FieldDescriptor* field,
142 const absl::string_view resolved_field_name,
143 const absl::string_view resolved_upbc_name,
144 Output& output) {
145 if (field->has_presence()) {
146 output("void clear_$0() { $2_clear_$1(msg_); }\n", resolved_field_name,
147 resolved_upbc_name, MessageName(desc));
148 }
149}
150
151void WriteMapFieldAccessors(const protobuf::Descriptor* desc,
152 const protobuf::FieldDescriptor* field,
153 const absl::string_view resolved_field_name,
154 const absl::string_view resolved_upbc_name,
155 Output& output) {
156 const protobuf::Descriptor* entry = field->message_type();
157 const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1);
158 const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2);
159 output(
160 R"cc(
161 inline size_t $0_size() const { return $1_$3_size(msg_); }
162 inline void clear_$0() { $1_clear_$3(msg_); }
163 void delete_$0($2 key);
164 )cc",
165 resolved_field_name, MessageName(desc), CppConstType(key),
166 resolved_upbc_name);
167
168 if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
169 output(
170 R"cc(
171 bool set_$0($1 key, $3 value);
172 bool set_$0($1 key, $4 value);
173 absl::StatusOr<$3> get_$0($1 key);
174 )cc",
175 resolved_field_name, CppConstType(key), CppConstType(val),
176 MessagePtrConstType(val, /* is_const */ true),
177 MessagePtrConstType(val, /* is_const */ false));
178 } else {
179 output(
180 R"cc(
181 bool set_$0($1 key, $2 value);
182 absl::StatusOr<$2> get_$0($1 key);
183 )cc",
184 resolved_field_name, CppConstType(key), CppConstType(val));
185 }
186}
187
188void WriteAccessorsInSource(const protobuf::Descriptor* desc, Output& output) {
189 std::string class_name = ClassName(desc);
190 absl::StrAppend(&class_name, "Access");
191 output("namespace internal {\n");
192 const char arena_expression[] = "arena_";
193 auto field_names = CreateFieldNameMap(desc);
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700194 auto upbc_field_names = upb::generator::CreateFieldNameMap(desc);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700195
196 // Generate const methods.
197 OutputIndenter i(output);
198 for (const auto* field : FieldNumberOrder(desc)) {
199 std::string resolved_field_name = ResolveFieldName(field, field_names);
200 std::string resolved_upbc_name =
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700201 upb::generator::ResolveFieldName(field, upbc_field_names);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700202 if (field->is_map()) {
203 WriteMapAccessorDefinitions(desc, field, resolved_field_name, class_name,
204 output);
205 } else if (desc->options().map_entry()) {
206 // TODO Implement map entry
207 } else if (field->is_repeated()) {
208 if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
209 WriteRepeatedMessageAccessor(desc, field, resolved_field_name,
210 class_name, output);
211 } else if (field->cpp_type() ==
212 protobuf::FieldDescriptor::CPPTYPE_STRING) {
213 WriteRepeatedStringAccessor(desc, field, resolved_field_name,
214 class_name, output);
215 } else {
216 WriteRepeatedScalarAccessor(desc, field, resolved_field_name,
217 class_name, output);
218 }
219 } else {
220 // non-repeated field.
221 if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
222 output(
223 R"cc(
224 $1 $0::$2() const {
225 return ::protos::UpbStrToStringView($3_$4(msg_));
226 }
227 )cc",
228 class_name, CppConstType(field), resolved_field_name,
229 MessageName(desc), resolved_upbc_name);
230 // Set string.
231 output(
232 R"cc(
233 void $0::set_$2($1 value) {
234 $4_set_$3(msg_, ::protos::UpbStrFromStringView(value, $5));
235 }
236 )cc",
237 class_name, CppConstType(field), resolved_field_name,
238 resolved_upbc_name, MessageName(desc), arena_expression);
239 } else if (field->cpp_type() ==
240 protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
241 output(
242 R"cc(
243 $1 $0::$2() const {
244 if (!has_$2()) {
245 return $4::default_instance();
246 }
247 return ::protos::internal::CreateMessage<$4>(
248 (upb_Message*)($3_$5(msg_)), arena_);
249 }
250 )cc",
251 class_name, MessagePtrConstType(field, /* is_const */ true),
252 resolved_field_name, MessageName(desc),
253 MessageBaseType(field, /* maybe_const */ false),
254 resolved_upbc_name);
255
256 output(
257 R"cc(
258 $1 $0::mutable_$2() {
259 return ::protos::internal::CreateMessageProxy<$4>(
260 (upb_Message*)($3_mutable_$5(msg_, $6)), $6);
261 }
262 )cc",
263 class_name, MessagePtrConstType(field, /* is_const */ false),
264 resolved_field_name, MessageName(desc),
265 MessageBaseType(field, /* maybe_const */ false), resolved_upbc_name,
266 arena_expression);
267 }
268 }
269 }
270 output("\n");
271 output("} // namespace internal\n\n");
272}
273
274void WriteMapAccessorDefinitions(const protobuf::Descriptor* message,
275 const protobuf::FieldDescriptor* field,
276 const absl::string_view resolved_field_name,
277 const absl::string_view class_name,
278 Output& output) {
279 const protobuf::Descriptor* entry = field->message_type();
280 const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1);
281 const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2);
282 absl::string_view upbc_name = field->name();
283 absl::string_view converted_key_name = "key";
284 absl::string_view optional_conversion_code = "";
285
286 if (key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
287 // Insert conversion from absl::string_view to upb_StringView.
288 // Creates upb_StringView on stack to prevent allocation.
289 converted_key_name = "upb_key";
290 optional_conversion_code =
291 "upb_StringView upb_key = {key.data(), key.size()};\n";
292 }
293 if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
294 output(
295 R"cc(
296 bool $0::set_$1($2 key, $3 value) {
297 upb_Message* clone = upb_Message_DeepClone(
298 ::protos::internal::PrivateAccess::GetInternalMsg(value), &$9,
299 arena_);
300 $6return $4_$8_set(msg_, $7, ($5*)clone, arena_);
301 }
302 )cc",
303 class_name, resolved_field_name, CppConstType(key),
304 MessagePtrConstType(val, /* is_const */ true), MessageName(message),
305 MessageName(val->message_type()), optional_conversion_code,
306 converted_key_name, upbc_name,
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700307 ::upb::generator::MessageInit(val->message_type()->full_name()));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700308 output(
309 R"cc(
310 bool $0::set_$1($2 key, $3 value) {
311 upb_Message* clone = upb_Message_DeepClone(
312 ::protos::internal::PrivateAccess::GetInternalMsg(value), &$9,
313 arena_);
314 $6return $4_$8_set(msg_, $7, ($5*)clone, arena_);
315 }
316 )cc",
317 class_name, resolved_field_name, CppConstType(key),
318 MessagePtrConstType(val, /* is_const */ false), MessageName(message),
319 MessageName(val->message_type()), optional_conversion_code,
320 converted_key_name, upbc_name,
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700321 ::upb::generator::MessageInit(val->message_type()->full_name()));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700322 output(
323 R"cc(
324 absl::StatusOr<$3> $0::get_$1($2 key) {
325 $5* msg_value;
326 $7bool success = $4_$9_get(msg_, $8, &msg_value);
327 if (success) {
Eric Salob997cb62023-12-21 08:09:54 -0800328 return ::protos::internal::CreateMessage<$6>(UPB_UPCAST(msg_value), arena_);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700329 }
330 return absl::NotFoundError("");
331 }
332 )cc",
333 class_name, resolved_field_name, CppConstType(key),
334 MessagePtrConstType(val, /* is_const */ true), MessageName(message),
335 MessageName(val->message_type()),
336 QualifiedClassName(val->message_type()), optional_conversion_code,
337 converted_key_name, upbc_name);
338 output(
339 R"cc(
340 void $0::delete_$1($2 key) { $6$4_$8_delete(msg_, $7); }
341 )cc",
342 class_name, resolved_field_name, CppConstType(key),
343 MessagePtrConstType(val, /* is_const */ false), MessageName(message),
344 MessageName(val->message_type()), optional_conversion_code,
345 converted_key_name, upbc_name);
346 } else if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
347 output(
348 R"cc(
349 bool $0::set_$1($2 key, $3 value) {
350 $5return $4_$7_set(msg_, $6,
351 ::protos::UpbStrFromStringView(value, arena_),
352 arena_);
353 }
354 )cc",
355 class_name, resolved_field_name, CppConstType(key), CppConstType(val),
356 MessageName(message), optional_conversion_code, converted_key_name,
357 upbc_name);
358 output(
359 R"cc(
360 absl::StatusOr<$3> $0::get_$1($2 key) {
361 upb_StringView value;
362 $5bool success = $4_$7_get(msg_, $6, &value);
363 if (success) {
364 return absl::string_view(value.data, value.size);
365 }
366 return absl::NotFoundError("");
367 }
368 )cc",
369 class_name, resolved_field_name, CppConstType(key), CppConstType(val),
370 MessageName(message), optional_conversion_code, converted_key_name,
371 upbc_name);
372 output(
373 R"cc(
374 void $0::delete_$1($2 key) { $5$4_$7_delete(msg_, $6); }
375 )cc",
376 class_name, resolved_field_name, CppConstType(key), CppConstType(val),
377 MessageName(message), optional_conversion_code, converted_key_name,
378 upbc_name);
379 } else {
380 output(
381 R"cc(
382 bool $0::set_$1($2 key, $3 value) {
383 $5return $4_$7_set(msg_, $6, value, arena_);
384 }
385 )cc",
386 class_name, resolved_field_name, CppConstType(key), CppConstType(val),
387 MessageName(message), optional_conversion_code, converted_key_name,
388 upbc_name);
389 output(
390 R"cc(
391 absl::StatusOr<$3> $0::get_$1($2 key) {
392 $3 value;
393 $5bool success = $4_$7_get(msg_, $6, &value);
394 if (success) {
395 return value;
396 }
397 return absl::NotFoundError("");
398 }
399 )cc",
400 class_name, resolved_field_name, CppConstType(key), CppConstType(val),
401 MessageName(message), optional_conversion_code, converted_key_name,
402 upbc_name);
403 output(
404 R"cc(
405 void $0::delete_$1($2 key) { $5$4_$7_delete(msg_, $6); }
406 )cc",
407 class_name, resolved_field_name, CppConstType(key), CppConstType(val),
408 MessageName(message), optional_conversion_code, converted_key_name,
409 upbc_name);
410 }
411}
412
413void WriteUsingAccessorsInHeader(const protobuf::Descriptor* desc,
414 MessageClassType handle_type, Output& output) {
415 bool read_only = handle_type == MessageClassType::kMessageCProxy;
416
417 // Generate const methods.
418 OutputIndenter i(output);
419 std::string class_name = ClassName(desc);
420 auto field_names = CreateFieldNameMap(desc);
421
422 for (const auto* field : FieldNumberOrder(desc)) {
423 std::string resolved_field_name = ResolveFieldName(field, field_names);
424 // Generate hazzer (if any).
425 if (field->has_presence()) {
426 output("using $0Access::has_$1;\n", class_name, resolved_field_name);
427 if (!read_only) {
428 output("using $0Access::clear_$1;\n", class_name, resolved_field_name);
429 }
430 }
431 if (field->is_map()) {
432 output(
433 R"cc(
434 using $0Access::$1_size;
435 using $0Access::get_$1;
436 )cc",
437 class_name, resolved_field_name);
438 if (!read_only) {
439 output(
440 R"cc(
441 using $0Access::clear_$1;
442 using $0Access::delete_$1;
443 using $0Access::set_$1;
444 )cc",
445 class_name, resolved_field_name);
446 }
447 } else if (desc->options().map_entry()) {
448 // TODO Implement map entry
449 } else if (field->is_repeated()) {
450 WriteRepeatedFieldUsingAccessors(field, class_name, resolved_field_name,
451 output, read_only);
452 } else {
453 if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
454 output("using $0Access::$1;\n", ClassName(desc), resolved_field_name);
455 if (!read_only) {
456 output("using $0Access::mutable_$1;\n", class_name,
457 resolved_field_name);
458 }
459 } else {
460 output("using $0Access::$1;\n", class_name, resolved_field_name);
461 if (!read_only) {
462 output("using $0Access::set_$1;\n", class_name, resolved_field_name);
463 }
464 }
465 }
466 }
467 for (int i = 0; i < desc->real_oneof_decl_count(); ++i) {
468 const protobuf::OneofDescriptor* oneof = desc->oneof_decl(i);
469 output("using $0Access::$1_case;\n", class_name, oneof->name());
470 output("using $0Access::$1Case;\n", class_name,
471 ToCamelCase(oneof->name(), /*lower_first=*/false));
472 for (int j = 0; j < oneof->field_count(); ++j) {
473 const protobuf::FieldDescriptor* field = oneof->field(j);
474 output("using $0Access::k$1;\n", class_name,
475 ToCamelCase(field->name(), /*lower_first=*/false),
476 field->number());
477 }
478 output("using $0Access::$1_NOT_SET;\n", class_name,
479 absl::AsciiStrToUpper(oneof->name()));
480 }
481}
482
483void WriteOneofAccessorsInHeader(const protobuf::Descriptor* desc,
484 Output& output) {
485 // Generate const methods.
486 OutputIndenter i(output);
487 std::string class_name = ClassName(desc);
488 auto field_names = CreateFieldNameMap(desc);
489 for (int i = 0; i < desc->real_oneof_decl_count(); ++i) {
490 const protobuf::OneofDescriptor* oneof = desc->oneof_decl(i);
491 output("enum $0Case {\n",
492 ToCamelCase(oneof->name(), /*lower_first=*/false));
493 for (int j = 0; j < oneof->field_count(); ++j) {
494 const protobuf::FieldDescriptor* field = oneof->field(j);
495 output(" k$0 = $1,\n", ToCamelCase(field->name(), /*lower_first=*/false),
496 field->number());
497 }
498 output(" $0_NOT_SET = 0,\n", absl::AsciiStrToUpper(oneof->name()));
499 output("};\n\n");
500 output("$0Case $1_case() const {\n",
501 ToCamelCase(oneof->name(), /*lower_first=*/false), oneof->name());
502 for (int j = 0; j < oneof->field_count(); ++j) {
503 const protobuf::FieldDescriptor* field = oneof->field(j);
504 std::string resolved_field_name = ResolveFieldName(field, field_names);
505 output(" if (has_$0()) { return k$1; }\n", resolved_field_name,
506 ToCamelCase(field->name(), /*lower_first=*/false));
507 }
508 output(" return $0_NOT_SET;\n", absl::AsciiStrToUpper(oneof->name()));
509 output("}\n;");
510 }
511}
512
513std::string ResolveFieldName(const protobuf::FieldDescriptor* field,
514 const NameToFieldDescriptorMap& field_names) {
515 // C++ implementation specific reserved names.
516 static const auto& kReservedNames =
517 *new absl::flat_hash_set<absl::string_view>({
518 "msg",
519 "msg_",
520 "arena",
521 "arena_",
522 });
523
524 // C++ specific prefixes used by code generator for field access.
525 static constexpr absl::string_view kClearMethodPrefix = "clear_";
526 static constexpr absl::string_view kSetMethodPrefix = "set_";
527 static constexpr absl::string_view kHasMethodPrefix = "has_";
528 static constexpr absl::string_view kDeleteMethodPrefix = "delete_";
529 static constexpr absl::string_view kAddToRepeatedMethodPrefix = "add_";
530 static constexpr absl::string_view kResizeArrayMethodPrefix = "resize_";
531
532 // List of generated accessor prefixes to check against.
533 // Example:
534 // optional repeated string phase = 236;
535 // optional bool clear_phase = 237;
536 static constexpr absl::string_view kAccessorPrefixes[] = {
537 kClearMethodPrefix, kDeleteMethodPrefix, kAddToRepeatedMethodPrefix,
538 kResizeArrayMethodPrefix, kSetMethodPrefix, kHasMethodPrefix};
539
540 absl::string_view field_name = field->name();
541 if (kReservedNames.count(field_name) > 0) {
542 if (absl::EndsWith(field_name, "_")) {
543 return absl::StrCat(field_name, "_");
544 } else {
545 return absl::StrCat(field_name, "__");
546 }
547 }
548 for (const auto prefix : kAccessorPrefixes) {
549 // If field name starts with a prefix such as clear_ and the proto
550 // contains a field name with trailing end, depending on type of field
551 // (repeated, map, message) we have a conflict to resolve.
552 if (absl::StartsWith(field_name, prefix)) {
553 auto match = field_names.find(field_name.substr(prefix.size()));
554 if (match != field_names.end()) {
555 const auto* candidate = match->second;
556 if (candidate->is_repeated() || candidate->is_map() ||
557 (candidate->cpp_type() ==
558 protobuf::FieldDescriptor::CPPTYPE_STRING &&
559 prefix == kClearMethodPrefix) ||
560 prefix == kSetMethodPrefix || prefix == kHasMethodPrefix) {
561 return absl::StrCat(field_name, "_");
562 }
563 }
564 }
565 }
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700566 return upb::generator::ResolveKeywordConflict(std::string(field_name));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700567}
568
569} // namespace protos_generator