• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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