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 "google/protobuf/compiler/hpb/names.h"
9
10 #include <string>
11
12 #include "absl/strings/string_view.h"
13 #include "google/protobuf/compiler/code_generator.h"
14 #include "google/protobuf/compiler/hpb/keywords.h"
15
16 namespace google::protobuf::hpb_generator {
17 namespace protobuf = ::proto2;
18
19 namespace {
20
21 // TODO: b/346865271 append ::hpb instead of ::protos after namespace swap
NamespaceFromPackageName(absl::string_view package_name)22 std::string NamespaceFromPackageName(absl::string_view package_name) {
23 return absl::StrCat(absl::StrReplaceAll(package_name, {{".", "::"}}),
24 "::protos");
25 }
26
DotsToColons(const absl::string_view name)27 std::string DotsToColons(const absl::string_view name) {
28 return absl::StrReplaceAll(name, {{".", "::"}});
29 }
30
Namespace(const absl::string_view package)31 std::string Namespace(const absl::string_view package) {
32 if (package.empty()) return "";
33 return "::" + DotsToColons(package);
34 }
35
36 // Return the qualified C++ name for a file level symbol.
QualifiedFileLevelSymbol(const protobuf::FileDescriptor * file,const std::string & name)37 std::string QualifiedFileLevelSymbol(const protobuf::FileDescriptor* file,
38 const std::string& name) {
39 if (file->package().empty()) {
40 return absl::StrCat("::", name);
41 }
42 // Append ::protos postfix to package name.
43 return absl::StrCat(Namespace(file->package()), "::protos::", name);
44 }
45
CppTypeInternal(const protobuf::FieldDescriptor * field,bool is_const,bool is_type_parameter)46 std::string CppTypeInternal(const protobuf::FieldDescriptor* field,
47 bool is_const, bool is_type_parameter) {
48 std::string maybe_const = is_const ? "const " : "";
49 switch (field->cpp_type()) {
50 case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
51 if (is_type_parameter) {
52 return absl::StrCat(maybe_const,
53 QualifiedClassName(field->message_type()));
54 } else {
55 return absl::StrCat(maybe_const,
56 QualifiedClassName(field->message_type()), "*");
57 }
58 }
59 case protobuf::FieldDescriptor::CPPTYPE_BOOL:
60 return "bool";
61 case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
62 return "float";
63 case protobuf::FieldDescriptor::CPPTYPE_INT32:
64 case protobuf::FieldDescriptor::CPPTYPE_ENUM:
65 return "int32_t";
66 case protobuf::FieldDescriptor::CPPTYPE_UINT32:
67 return "uint32_t";
68 case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
69 return "double";
70 case protobuf::FieldDescriptor::CPPTYPE_INT64:
71 return "int64_t";
72 case protobuf::FieldDescriptor::CPPTYPE_UINT64:
73 return "uint64_t";
74 case protobuf::FieldDescriptor::CPPTYPE_STRING:
75 return "absl::string_view";
76 default:
77 ABSL_LOG(FATAL) << "Unexpected type: " << field->cpp_type();
78 }
79 }
80
81 } // namespace
82
ClassName(const protobuf::Descriptor * descriptor)83 std::string ClassName(const protobuf::Descriptor* descriptor) {
84 const protobuf::Descriptor* parent = descriptor->containing_type();
85 std::string res;
86 // Classes in global namespace without package names are prefixed
87 // by hpb_ to avoid collision with C compiler structs defined in
88 // proto.upb.h.
89 if ((parent && parent->file()->package().empty()) ||
90 descriptor->file()->package().empty()) {
91 res = std::string(kNoPackageNamePrefix);
92 }
93 if (parent) res += ClassName(parent) + "_";
94 absl::StrAppend(&res, descriptor->name());
95 return ResolveKeywordConflict(res);
96 }
97
QualifiedClassName(const protobuf::Descriptor * descriptor)98 std::string QualifiedClassName(const protobuf::Descriptor* descriptor) {
99 return QualifiedFileLevelSymbol(descriptor->file(), ClassName(descriptor));
100 }
101
QualifiedInternalClassName(const protobuf::Descriptor * descriptor)102 std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor) {
103 return QualifiedFileLevelSymbol(
104 descriptor->file(), absl::StrCat("internal::", ClassName(descriptor)));
105 }
106
CppSourceFilename(const google::protobuf::FileDescriptor * file)107 std::string CppSourceFilename(const google::protobuf::FileDescriptor* file) {
108 return compiler::StripProto(file->name()) + ".upb.proto.cc";
109 }
110
ForwardingHeaderFilename(const google::protobuf::FileDescriptor * file)111 std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file) {
112 return compiler::StripProto(file->name()) + ".upb.fwd.h";
113 }
114
UpbCFilename(const google::protobuf::FileDescriptor * file)115 std::string UpbCFilename(const google::protobuf::FileDescriptor* file) {
116 return compiler::StripProto(file->name()) + ".upb.h";
117 }
118
CppHeaderFilename(const google::protobuf::FileDescriptor * file)119 std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file) {
120 return compiler::StripProto(file->name()) + ".upb.proto.h";
121 }
122
WriteStartNamespace(const protobuf::FileDescriptor * file,Output & output)123 void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output) {
124 // Skip namespace generation if package name is not specified.
125 if (file->package().empty()) {
126 return;
127 }
128
129 output("namespace $0 {\n\n", NamespaceFromPackageName(file->package()));
130 }
131
WriteEndNamespace(const protobuf::FileDescriptor * file,Output & output)132 void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output) {
133 if (file->package().empty()) {
134 return;
135 }
136 output("} // namespace $0\n\n", NamespaceFromPackageName(file->package()));
137 }
138
CppConstType(const protobuf::FieldDescriptor * field)139 std::string CppConstType(const protobuf::FieldDescriptor* field) {
140 return CppTypeInternal(field, /* is_const= */ true,
141 /* is_type_parameter= */ false);
142 }
143
CppTypeParameterName(const protobuf::FieldDescriptor * field)144 std::string CppTypeParameterName(const protobuf::FieldDescriptor* field) {
145 return CppTypeInternal(field, /* is_const= */ false,
146 /* is_type_parameter= */ true);
147 }
148
MessageBaseType(const protobuf::FieldDescriptor * field,bool is_const)149 std::string MessageBaseType(const protobuf::FieldDescriptor* field,
150 bool is_const) {
151 ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
152 std::string maybe_const = is_const ? "const " : "";
153 return maybe_const + QualifiedClassName(field->message_type());
154 }
155
MessagePtrConstType(const protobuf::FieldDescriptor * field,bool is_const)156 std::string MessagePtrConstType(const protobuf::FieldDescriptor* field,
157 bool is_const) {
158 ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
159 std::string maybe_const = is_const ? "const " : "";
160 return "::hpb::Ptr<" + maybe_const +
161 QualifiedClassName(field->message_type()) + ">";
162 }
163
MessageCProxyType(const protobuf::FieldDescriptor * field,bool is_const)164 std::string MessageCProxyType(const protobuf::FieldDescriptor* field,
165 bool is_const) {
166 ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
167 std::string maybe_const = is_const ? "const " : "";
168 return maybe_const + QualifiedInternalClassName(field->message_type()) +
169 "CProxy";
170 }
171
MessageProxyType(const protobuf::FieldDescriptor * field,bool is_const)172 std::string MessageProxyType(const protobuf::FieldDescriptor* field,
173 bool is_const) {
174 ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
175 std::string maybe_const = is_const ? "const " : "";
176 return maybe_const + QualifiedInternalClassName(field->message_type()) +
177 "Proxy";
178 }
179
180 } // namespace protobuf
181 } // namespace google::hpb_generator
182