| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2023 Google LLC. All rights reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file or at | |
| // https://developers.google.com/open-source/licenses/bsd | |
| #include "upb_generator/c/names.h" | |
| #include <array> | |
| #include <cstdint> | |
| #include <string> | |
| #include <vector> | |
| #include "absl/container/flat_hash_map.h" | |
| #include "absl/strings/match.h" | |
| #include "absl/strings/str_cat.h" | |
| #include "absl/strings/str_join.h" | |
| #include "absl/strings/str_replace.h" | |
| #include "absl/strings/str_split.h" | |
| #include "absl/strings/string_view.h" | |
| #include "upb_generator/c/names_internal.h" | |
| namespace upb { | |
| namespace generator { | |
| namespace { | |
| std::string ToCIdent(absl::string_view str) { | |
| return absl::StrReplaceAll(str, {{".", "_"}, {"/", "_"}, {"-", "_"}}); | |
| } | |
| } // namespace | |
| std::string CApiHeaderFilename(absl::string_view proto_filename) { | |
| return CApiHeaderFilename(proto_filename, false); | |
| } | |
| std::string CApiMessageType(absl::string_view full_name) { | |
| return ToCIdent(full_name); | |
| } | |
| std::string CApiEnumType(absl::string_view full_name) { | |
| return ToCIdent(full_name); | |
| } | |
| std::string CApiEnumValueSymbol(absl::string_view full_name) { | |
| return ToCIdent(full_name); | |
| } | |
| std::string CApiExtensionIdentBase(absl::string_view full_name) { | |
| std::vector<std::string> parts = absl::StrSplit(full_name, '.'); | |
| parts.pop_back(); | |
| return ToCIdent(absl::StrJoin(parts, ".")); | |
| } | |
| std::string CApiOneofIdentBase(absl::string_view full_name) { | |
| return ToCIdent(full_name); | |
| } | |
| namespace { | |
| struct Prefix { | |
| absl::string_view name; | |
| uint32_t conflict_set; | |
| }; | |
| constexpr uint32_t kAnyField = UINT32_MAX; | |
| // Prefixes used by C code generator for field access. | |
| static constexpr std::array<Prefix, 7> kPrefixes{ | |
| Prefix{"clear_", kAnyField}, Prefix{"delete_", kContainerField}, | |
| Prefix{"add_", kContainerField}, Prefix{"resize_", kContainerField}, | |
| Prefix{"set_", kAnyField}, Prefix{"has_", kAnyField}, | |
| Prefix{"mutable_", kAnyField}, | |
| }; | |
| static constexpr std::array<absl::string_view, 5> kReservedNames{ | |
| "new", "parse", "parse_ex", "serialize", "serialize_ex", | |
| }; | |
| bool IsReservedName(absl::string_view name) { | |
| for (const auto& reserved : kReservedNames) { | |
| if (name == reserved) return true; | |
| } | |
| return false; | |
| } | |
| bool HasConflict(absl::string_view name, | |
| const absl::flat_hash_map<std::string, FieldClass>& fields) { | |
| if (IsReservedName(name)) return true; | |
| for (const auto& prefix : kPrefixes) { | |
| if (!absl::StartsWith(name, prefix.name)) continue; | |
| auto match = fields.find(name.substr(prefix.name.size())); | |
| if (match == fields.end()) continue; | |
| if (prefix.conflict_set & match->second) return true; | |
| } | |
| return false; | |
| } | |
| } // namespace | |
| NameMangler::NameMangler( | |
| const absl::flat_hash_map<std::string, FieldClass>& fields) { | |
| for (const auto& pair : fields) { | |
| const std::string& field_name = pair.first; | |
| if (HasConflict(field_name, fields)) { | |
| names_.emplace(field_name, absl::StrCat(field_name, "_")); | |
| } | |
| } | |
| } | |
| } // namespace generator | |
| } // namespace upb |