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