Imported Upstream version 1.41.0
[platform/upstream/grpc.git] / third_party / upb / upbc / protoc-gen-upbdefs.cc
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" AND
16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY
19 // DIRECT, 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 <memory>
27
28 #include "google/protobuf/compiler/code_generator.h"
29 #include "google/protobuf/compiler/plugin.h"
30 #include "google/protobuf/descriptor.h"
31 #include "google/protobuf/descriptor.pb.h"
32 #include "upbc/common.h"
33
34 namespace upbc {
35 namespace {
36
37 namespace protoc = ::google::protobuf::compiler;
38 namespace protobuf = ::google::protobuf;
39
40 std::string DefInitSymbol(const protobuf::FileDescriptor *file) {
41   return ToCIdent(file->name()) + "_upbdefinit";
42 }
43
44 static std::string DefHeaderFilename(std::string proto_filename) {
45   return StripExtension(proto_filename) + ".upbdefs.h";
46 }
47
48 static std::string DefSourceFilename(std::string proto_filename) {
49   return StripExtension(proto_filename) + ".upbdefs.c";
50 }
51
52 void GenerateMessageDefAccessor(const protobuf::Descriptor* d, Output& output) {
53   output("UPB_INLINE const upb_msgdef *$0_getmsgdef(upb_symtab *s) {\n",
54          ToCIdent(d->full_name()));
55   output("  _upb_symtab_loaddefinit(s, &$0);\n", DefInitSymbol(d->file()));
56   output("  return upb_symtab_lookupmsg(s, \"$0\");\n", d->full_name());
57   output("}\n");
58   output("\n");
59
60   for (int i = 0; i < d->nested_type_count(); i++) {
61     GenerateMessageDefAccessor(d->nested_type(i), output);
62   }
63 }
64
65 void WriteDefHeader(const protobuf::FileDescriptor* file, Output& output) {
66   EmitFileWarning(file, output);
67
68   output(
69       "#ifndef $0_UPBDEFS_H_\n"
70       "#define $0_UPBDEFS_H_\n\n"
71       "#include \"upb/def.h\"\n"
72       "#include \"upb/port_def.inc\"\n"
73       "#ifdef __cplusplus\n"
74       "extern \"C\" {\n"
75       "#endif\n\n",
76       ToPreproc(file->name()));
77
78   output("#include \"upb/def.h\"\n");
79   output("\n");
80   output("#include \"upb/port_def.inc\"\n");
81   output("\n");
82
83   output("extern upb_def_init $0;\n", DefInitSymbol(file));
84   output("\n");
85
86   for (int i = 0; i < file->message_type_count(); i++) {
87     GenerateMessageDefAccessor(file->message_type(i), output);
88   }
89
90   output(
91       "#ifdef __cplusplus\n"
92       "}  /* extern \"C\" */\n"
93       "#endif\n"
94       "\n"
95       "#include \"upb/port_undef.inc\"\n"
96       "\n"
97       "#endif  /* $0_UPBDEFS_H_ */\n",
98       ToPreproc(file->name()));
99 }
100
101
102 void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) {
103   EmitFileWarning(file, output);
104
105   output("#include \"upb/def.h\"\n");
106   output("#include \"$0\"\n", DefHeaderFilename(file->name()));
107   output("\n");
108
109   for (int i = 0; i < file->dependency_count(); i++) {
110     output("extern upb_def_init $0;\n", DefInitSymbol(file->dependency(i)));
111   }
112
113   std::vector<const protobuf::Descriptor*> file_messages =
114       SortedMessages(file);
115
116   for (auto message : file_messages) {
117     output("extern const upb_msglayout $0;\n", MessageInit(message));
118   }
119   output("\n");
120
121   if (!file_messages.empty()) {
122     output("static const upb_msglayout *layouts[$0] = {\n", file_messages.size());
123     for (auto message : file_messages) {
124       output("  &$0,\n", MessageInit(message));
125     }
126     output("};\n");
127     output("\n");
128   }
129
130   protobuf::FileDescriptorProto file_proto;
131   file->CopyTo(&file_proto);
132   std::string file_data;
133   file_proto.SerializeToString(&file_data);
134
135   output("static const char descriptor[$0] = {", file_data.size());
136
137   // C90 only guarantees that strings can be up to 509 characters, and some
138   // implementations have limits here (for example, MSVC only allows 64k:
139   // https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/fatal-error-c1091.
140   // So we always emit an array instead of a string.
141   for (size_t i = 0; i < file_data.size();) {
142     for (size_t j = 0; j < 25 && i < file_data.size(); ++i, ++j) {
143       output("'$0', ", absl::CEscape(file_data.substr(i, 1)));
144     }
145     output("\n");
146   }
147   output("};\n\n");
148
149   output("static upb_def_init *deps[$0] = {\n", file->dependency_count() + 1);
150   for (int i = 0; i < file->dependency_count(); i++) {
151     output("  &$0,\n", DefInitSymbol(file->dependency(i)));
152   }
153   output("  NULL\n");
154   output("};\n");
155   output("\n");
156
157   output("upb_def_init $0 = {\n", DefInitSymbol(file));
158   output("  deps,\n");
159   if (file_messages.empty()) {
160     output("  NULL,\n");
161   } else {
162     output("  layouts,\n");
163   }
164   output("  \"$0\",\n", file->name());
165   output("  UPB_STRVIEW_INIT(descriptor, $0)\n", file_data.size());
166   output("};\n");
167 }
168
169 class Generator : public protoc::CodeGenerator {
170   ~Generator() override {}
171   bool Generate(const protobuf::FileDescriptor* file,
172                 const std::string& parameter, protoc::GeneratorContext* context,
173                 std::string* error) const override;
174   uint64_t GetSupportedFeatures() const override {
175     return FEATURE_PROTO3_OPTIONAL;
176   }
177 };
178
179 bool Generator::Generate(const protobuf::FileDescriptor* file,
180                          const std::string& parameter,
181                          protoc::GeneratorContext* context,
182                          std::string* error) const {
183   std::vector<std::pair<std::string, std::string>> params;
184   google::protobuf::compiler::ParseGeneratorParameter(parameter, &params);
185
186   for (const auto& pair : params) {
187     *error = "Unknown parameter: " + pair.first;
188     return false;
189   }
190
191   Output h_def_output(context->Open(DefHeaderFilename(file->name())));
192   WriteDefHeader(file, h_def_output);
193
194   Output c_def_output(context->Open(DefSourceFilename(file->name())));
195   WriteDefSource(file, c_def_output);
196
197   return true;
198 }
199
200 }  // namespace
201 }  // namespace upbc
202
203 int main(int argc, char** argv) {
204   std::unique_ptr<google::protobuf::compiler::CodeGenerator> generator(
205       new upbc::Generator());
206   return google::protobuf::compiler::PluginMain(argc, argv, generator.get());
207 }