Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(431)

Side by Side Diff: components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc

Issue 2145423002: ProtoZero plugin implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixes Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/tracing/test/example_messages.proto ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "proto_zero_generator.h" 5 #include "proto_zero_generator.h"
6 6
7 #include <map>
7 #include <memory> 8 #include <memory>
8 #include <string> 9 #include <string>
9 10
10 #include "third_party/protobuf/src/google/protobuf/descriptor.h" 11 #include "third_party/protobuf/src/google/protobuf/descriptor.h"
11 #include "third_party/protobuf/src/google/protobuf/io/printer.h" 12 #include "third_party/protobuf/src/google/protobuf/io/printer.h"
12 #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h" 13 #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h"
13 #include "third_party/protobuf/src/google/protobuf/stubs/strutil.h" 14 #include "third_party/protobuf/src/google/protobuf/stubs/strutil.h"
14 15
15 namespace tracing { 16 namespace tracing {
16 namespace proto { 17 namespace proto {
17 18
19 using google::protobuf::Descriptor; // Message descriptor.
20 using google::protobuf::EnumDescriptor;
21 using google::protobuf::EnumValueDescriptor;
22 using google::protobuf::FieldDescriptor;
18 using google::protobuf::FileDescriptor; 23 using google::protobuf::FileDescriptor;
19 using google::protobuf::StripSuffixString;
20 using google::protobuf::compiler::GeneratorContext; 24 using google::protobuf::compiler::GeneratorContext;
21 using google::protobuf::io::Printer; 25 using google::protobuf::io::Printer;
22 using google::protobuf::io::ZeroCopyOutputStream; 26 using google::protobuf::io::ZeroCopyOutputStream;
23 27
28 using google::protobuf::Split;
29 using google::protobuf::StripPrefixString;
30 using google::protobuf::StripString;
31 using google::protobuf::StripSuffixString;
32 using google::protobuf::UpperString;
33
24 namespace { 34 namespace {
25 35
26 class GeneratorJob { 36 class GeneratorJob {
27 public: 37 public:
28 GeneratorJob(const FileDescriptor *file, 38 GeneratorJob(const FileDescriptor *file,
29 Printer* stub_h_printer, 39 Printer* stub_h_printer,
30 Printer* stub_cc_printer) 40 Printer* stub_cc_printer)
31 : file_(file), 41 : source_(file),
32 stub_h_(stub_h_printer), 42 stub_h_(stub_h_printer),
33 stub_cc_(stub_cc_printer) {} 43 stub_cc_(stub_cc_printer) {}
34 44
35 bool GenerateStubs() { 45 bool GenerateStubs() {
36 stub_h_->Print( 46 Preprocess();
37 "// Autogenerated. DO NOT EDIT.\n" 47 GeneratePrologue();
38 "// Generated by: //components/tracing/proto_zero_plugin.\n\n" 48 for (const EnumDescriptor* enumeration: enums_)
39 "// Package: $package$\n", 49 GenerateEnumDescriptor(enumeration);
40 "package", file_->package()); 50 for (const Descriptor* message : messages_)
41 stub_cc_->Print( 51 GenerateMessageDescriptor(message);
42 "// Autogenerated. DO NOT EDIT.\n" 52 GenerateEpilogue();
43 "// Generated by: //components/tracing/proto_zero_plugin.\n\n" 53 return error_.empty();
44 "// This file intentionally left blank.\n");
45 // TODO(kraynov) Implement in the next CL (crbug.com/608721).
46 return true;
47 } 54 }
48 55
49 // If generator fails to produce stubs for a particular proto definitions 56 // If generator fails to produce stubs for a particular proto definitions
50 // it finishes with undefined output and writes the first error occured. 57 // it finishes with undefined output and writes the first error occured.
51 const std::string& GetFirstError() const { 58 const std::string& GetFirstError() const {
52 return error_; 59 return error_;
53 } 60 }
54 61
55 private: 62 private:
56 // Only the first error will be recorded. 63 // Only the first error will be recorded.
57 void Abort(const std::string& reason) { 64 void Abort(const std::string& reason) {
58 if (error_.empty()) { 65 if (error_.empty())
59 error_ = reason; 66 error_ = reason;
60 } 67 }
61 } 68
62 69 // Get full name (including outer descriptors) of proto descriptor.
63 const FileDescriptor* const file_; 70 template <class T>
71 inline std::string GetDescriptorName(const T* descriptor) {
72 if (!package_.empty()) {
73 return StripPrefixString(descriptor->full_name(), package_ + ".");
74 } else {
75 return descriptor->full_name();
76 }
77 }
78
79 // Get C++ class name corresponding to proto descriptor.
80 // Nested names are splitted by underscores. Underscores in type names aren't
81 // prohibited but not recommended in order to avoid name collisions.
82 template <class T>
83 inline std::string GetCppClassName(const T* descriptor, bool full = false) {
84 std::string name = GetDescriptorName(descriptor);
85 StripString(&name, ".", '_');
86 if (full)
87 name = full_namespace_prefix_ + name;
88 return name;
89 }
90
91 // Small enums can be written faster without involving VarInt encoder.
92 inline bool IsTinyEnumField(const FieldDescriptor* field) {
93 if (field->type() != FieldDescriptor::TYPE_ENUM)
94 return false;
95 const EnumDescriptor* enumeration = field->enum_type();
96
97 for (int i = 0; i < enumeration->value_count(); ++i) {
98 int32_t value = enumeration->value(i)->number();
99 if (value < 0 || value > 0x7F)
100 return false;
101 }
102 return true;
103 }
104
105 void Preprocess() {
106 // Package name maps to a series of namespaces.
107 package_ = source_->package();
108 namespaces_ = Split(package_, ".");
109 full_namespace_prefix_ = "::";
110 for (const std::string& ns : namespaces_)
111 full_namespace_prefix_ += ns + "::";
112
113 // Collect message descriptors in DFS order.
114 std::vector<const Descriptor*> stack;
115 for (int i = 0; i < source_->message_type_count(); ++i)
116 stack.push_back(source_->message_type(i));
117
118 while (!stack.empty()) {
119 const Descriptor* message = stack.back();
120 stack.pop_back();
121 messages_.push_back(message);
122 for (int i = 0; i < message->nested_type_count(); ++i) {
123 stack.push_back(message->nested_type(i));
124 }
125 }
126
127 // Collect enums.
128 for (int i = 0; i < source_->enum_type_count(); ++i)
129 enums_.push_back(source_->enum_type(i));
130
131 for (const Descriptor* message : messages_) {
132 for (int i = 0; i < message->enum_type_count(); ++i) {
133 enums_.push_back(message->enum_type(i));
134 }
135 }
136 }
137
138 // Print top header, namespaces and forward declarations.
139 void GeneratePrologue() {
140 std::string greeting =
141 "// Autogenerated. DO NOT EDIT.\n"
142 "// Protobuf compiler (protoc) has generated these stubs with\n"
143 "// //components/tracing/tools/proto_zero_plugin.\n";
144 std::string guard = package_ + "_" + source_->name() + "_H_";
145 UpperString(&guard);
146 StripString(&guard, ".-", '_');
147
148 stub_h_->Print(
149 "$greeting$\n"
150 "#ifndef $guard$\n"
151 "#define $guard$\n\n"
152 "#include <stddef.h>\n"
153 "#include <stdint.h>\n\n"
154 "#include \"components/tracing/core/proto_zero_message.h\"\n\n",
155 "greeting", greeting,
156 "guard", guard);
157 stub_cc_->Print(
158 "$greeting$\n"
159 "// This file intentionally left blank.\n",
160 "greeting", greeting);
161
162 // Print namespaces.
163 for (const std::string& ns : namespaces_)
164 stub_h_->Print("namespace $ns$ {\n", "ns", ns);
165 stub_h_->Print("\n");
166 // Print forward declarations.
167 for (const Descriptor* message : messages_) {
168 stub_h_->Print(
169 "class $class$;\n",
170 "class", GetCppClassName(message));
171 }
172 stub_h_->Print("\n");
173 }
174
175 void GenerateEnumDescriptor(const EnumDescriptor* enumeration) {
176 stub_h_->Print(
177 "enum $class$ {\n",
178 "class", GetCppClassName(enumeration));
179 stub_h_->Indent();
180
181 std::string value_name_prefix;
182 if (enumeration->containing_type() != nullptr)
183 value_name_prefix = GetCppClassName(enumeration) + "_";
184
185 for (int i = 0; i < enumeration->value_count(); ++i) {
186 const EnumValueDescriptor* value = enumeration->value(i);
187 stub_h_->Print(
188 "$name$ = $number$,\n",
189 "name", value_name_prefix + value->name(),
190 "number", std::to_string(value->number()));
191 }
192
193 stub_h_->Outdent();
194 stub_h_->Print("};\n\n");
195 }
196
197 void GenerateSimpleFieldDescriptor(const FieldDescriptor* field) {
198 std::map<std::string, std::string> setter;
199 setter["id"] = std::to_string(field->number());
200 setter["name"] = field->name();
201 setter["action"] = field->is_repeated() ? "add" : "set";
202
203 std::string appender;
204 std::string cpp_type;
205
206 switch (field->type()) {
207 case FieldDescriptor::TYPE_BOOL: {
208 appender = "AppendBool";
209 cpp_type = "bool";
210 break;
211 }
212 case FieldDescriptor::TYPE_INT32: {
213 appender = "AppendInt32";
214 cpp_type = "int32_t";
215 break;
216 }
217 case FieldDescriptor::TYPE_INT64: {
218 appender = "AppendInt64";
219 cpp_type = "int64_t";
220 break;
221 }
222 case FieldDescriptor::TYPE_UINT32: {
223 appender = "AppendUint32";
224 cpp_type = "uint32_t";
225 break;
226 }
227 case FieldDescriptor::TYPE_UINT64: {
228 appender = "AppendUint64";
229 cpp_type = "uint64_t";
230 break;
231 }
232 case FieldDescriptor::TYPE_SINT32: {
233 appender = "AppendSint32";
234 cpp_type = "int32_t";
235 break;
236 }
237 case FieldDescriptor::TYPE_SINT64: {
238 appender = "AppendSint64";
239 cpp_type = "int64_t";
240 break;
241 }
242 case FieldDescriptor::TYPE_FIXED32: {
243 appender = "AppendFixed32";
244 cpp_type = "uint32_t";
245 break;
246 }
247 case FieldDescriptor::TYPE_FIXED64: {
248 appender = "AppendFixed64";
249 cpp_type = "uint64_t";
250 break;
251 }
252 case FieldDescriptor::TYPE_SFIXED32: {
253 appender = "AppendSfixed32";
254 cpp_type = "int32_t";
255 break;
256 }
257 case FieldDescriptor::TYPE_SFIXED64: {
258 appender = "AppendSfixed64";
259 cpp_type = "int64_t";
260 break;
261 }
262 case FieldDescriptor::TYPE_FLOAT: {
263 appender = "AppendFloat";
264 cpp_type = "float";
265 break;
266 }
267 case FieldDescriptor::TYPE_DOUBLE: {
268 appender = "AppendDouble";
269 cpp_type = "double";
270 break;
271 }
272 case FieldDescriptor::TYPE_ENUM: {
273 appender = IsTinyEnumField(field) ? "AppendTinyNumber" : "AppendInt32";
274 cpp_type = GetCppClassName(field->enum_type(), true);
275 break;
276 }
277 case FieldDescriptor::TYPE_STRING: {
278 appender = "AppendString";
279 cpp_type = "const char*";
280 break;
281 }
282 case FieldDescriptor::TYPE_BYTES: {
283 stub_h_->Print(
284 setter,
285 "void $action$_$name$(const uint8_t* data, size_t size) {\n"
286 " // AppendBytes($id$, data, size);\n"
287 "}\n");
288 return;
289 }
290 default: {
291 Abort("Unsupported field type.");
292 return;
293 }
294 }
295 setter["appender"] = appender;
296 setter["cpp_type"] = cpp_type;
297 stub_h_->Print(
298 setter,
299 "void $action$_$name$($cpp_type$ value) {\n"
300 " // $appender$($id$, value);\n"
301 "}\n");
302 }
303
304 void GenerateNestedMessageFieldDescriptor(const FieldDescriptor* field) {
305 stub_h_->Print(
306 "$class$* $action$_$name$() {\n"
307 " return BeginNestedMessage<$class$>($id$);\n"
308 "}\n",
309 "id", std::to_string(field->number()),
310 "name", field->name(),
311 "action", field->is_repeated() ? "add" : "set",
312 "class", GetCppClassName(field->message_type()));
313 }
314
315 void GenerateMessageDescriptor(const Descriptor* message) {
316 stub_h_->Print(
317 "class $name$ : public ::tracing::v2::ProtoZeroMessage {\n"
318 " public:\n",
319 "name", GetCppClassName(message));
320 stub_h_->Indent();
321
322 // Using statements for nested messages.
323 for (int i = 0; i < message->nested_type_count(); ++i) {
324 const Descriptor* nested_message = message->nested_type(i);
325 stub_h_->Print(
326 "using $local_name$ = $global_name$;\n",
327 "local_name", nested_message->name(),
328 "global_name", GetCppClassName(nested_message, true));
329 }
330
331 // Using statements for nested enums.
332 for (int i = 0; i < message->enum_type_count(); ++i) {
333 const EnumDescriptor* nested_enum = message->enum_type(i);
334 stub_h_->Print(
335 "using $local_name$ = $global_name$;\n",
336 "local_name", nested_enum->name(),
337 "global_name", GetCppClassName(nested_enum, true));
338 }
339
340 // Values of nested enums.
341 for (int i = 0; i < message->enum_type_count(); ++i) {
342 const EnumDescriptor* nested_enum = message->enum_type(i);
343 std::string value_name_prefix = GetCppClassName(nested_enum) + "_";
344
345 for (int j = 0; j < nested_enum->value_count(); ++j) {
346 const EnumValueDescriptor* value = nested_enum->value(j);
347 stub_h_->Print(
348 "static const $class$ $name$ = $full_name$;\n",
349 "class", nested_enum->name(),
350 "name", value->name(),
351 "full_name", value_name_prefix + value->name());
352 }
353 }
354
355 // Fields descriptors.
356 for (int i = 0; i < message->field_count(); ++i) {
357 const FieldDescriptor* field = message->field(i);
358 if (field->is_packed()) {
359 Abort("Packed repeated fields are not supported.");
360 return;
361 }
362 if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
363 GenerateSimpleFieldDescriptor(field);
364 } else {
365 GenerateNestedMessageFieldDescriptor(field);
366 }
367 }
368
369 stub_h_->Outdent();
370 stub_h_->Print("};\n\n");
371 }
372
373 void GenerateEpilogue() {
374 for (unsigned i = 0; i < namespaces_.size(); ++i) {
375 stub_h_->Print("} // Namespace.\n");
376 }
377 stub_h_->Print("#endif // Include guard.\n");
378 }
379
380 const FileDescriptor* const source_;
64 Printer* const stub_h_; 381 Printer* const stub_h_;
65 Printer* const stub_cc_; 382 Printer* const stub_cc_;
66 std::string error_; 383 std::string error_;
384
385 std::string package_;
386 std::vector<std::string> namespaces_;
387 std::string full_namespace_prefix_;
388 std::vector<const Descriptor*> messages_;
389 std::vector<const EnumDescriptor*> enums_;
67 }; 390 };
68 391
69 } // namespace 392 } // namespace
70 393
71 ProtoZeroGenerator::ProtoZeroGenerator() { 394 ProtoZeroGenerator::ProtoZeroGenerator() {
72 } 395 }
73 396
74 ProtoZeroGenerator::~ProtoZeroGenerator() { 397 ProtoZeroGenerator::~ProtoZeroGenerator() {
75 } 398 }
76 399
(...skipping 17 matching lines...) Expand all
94 GeneratorJob job(file, &stub_h_printer, &stub_cc_printer); 417 GeneratorJob job(file, &stub_h_printer, &stub_cc_printer);
95 if (!job.GenerateStubs()) { 418 if (!job.GenerateStubs()) {
96 *error = job.GetFirstError(); 419 *error = job.GetFirstError();
97 return false; 420 return false;
98 } 421 }
99 return true; 422 return true;
100 } 423 }
101 424
102 } // namespace proto 425 } // namespace proto
103 } // namespace tracing 426 } // namespace tracing
OLDNEW
« no previous file with comments | « components/tracing/test/example_messages.proto ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698