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

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

Issue 2201393002: Tracing V2: Import support for protobuf plugin. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: forwards Created 4 years, 4 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
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 <map>
8 #include <memory> 8 #include <memory>
9 #include <set>
9 #include <string> 10 #include <string>
10 11
11 #include "third_party/protobuf/src/google/protobuf/descriptor.h" 12 #include "third_party/protobuf/src/google/protobuf/descriptor.h"
12 #include "third_party/protobuf/src/google/protobuf/io/printer.h" 13 #include "third_party/protobuf/src/google/protobuf/io/printer.h"
13 #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h" 14 #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h"
14 #include "third_party/protobuf/src/google/protobuf/stubs/strutil.h" 15 #include "third_party/protobuf/src/google/protobuf/stubs/strutil.h"
15 16
16 namespace tracing { 17 namespace tracing {
17 namespace proto { 18 namespace proto {
18 19
19 using google::protobuf::Descriptor; // Message descriptor. 20 using google::protobuf::Descriptor; // Message descriptor.
20 using google::protobuf::EnumDescriptor; 21 using google::protobuf::EnumDescriptor;
21 using google::protobuf::EnumValueDescriptor; 22 using google::protobuf::EnumValueDescriptor;
22 using google::protobuf::FieldDescriptor; 23 using google::protobuf::FieldDescriptor;
23 using google::protobuf::FileDescriptor; 24 using google::protobuf::FileDescriptor;
24 using google::protobuf::compiler::GeneratorContext; 25 using google::protobuf::compiler::GeneratorContext;
25 using google::protobuf::io::Printer; 26 using google::protobuf::io::Printer;
26 using google::protobuf::io::ZeroCopyOutputStream; 27 using google::protobuf::io::ZeroCopyOutputStream;
27 28
28 using google::protobuf::Split; 29 using google::protobuf::Split;
29 using google::protobuf::StripPrefixString; 30 using google::protobuf::StripPrefixString;
30 using google::protobuf::StripString; 31 using google::protobuf::StripString;
31 using google::protobuf::StripSuffixString; 32 using google::protobuf::StripSuffixString;
32 using google::protobuf::UpperString; 33 using google::protobuf::UpperString;
33 34
34 namespace { 35 namespace {
35 36
37 inline std::string ProtoStubName(const FileDescriptor* proto) {
38 return StripSuffixString(proto->name(), ".proto") + ".pbzero";
39 }
40
36 class GeneratorJob { 41 class GeneratorJob {
37 public: 42 public:
38 GeneratorJob(const FileDescriptor *file, 43 GeneratorJob(const FileDescriptor *file,
39 Printer* stub_h_printer, 44 Printer* stub_h_printer,
40 Printer* stub_cc_printer) 45 Printer* stub_cc_printer)
41 : source_(file), 46 : source_(file),
42 stub_h_(stub_h_printer), 47 stub_h_(stub_h_printer),
43 stub_cc_(stub_cc_printer) {} 48 stub_cc_(stub_cc_printer) {}
44 49
45 bool GenerateStubs() { 50 bool GenerateStubs() {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 const EnumDescriptor* enumeration = field->enum_type(); 100 const EnumDescriptor* enumeration = field->enum_type();
96 101
97 for (int i = 0; i < enumeration->value_count(); ++i) { 102 for (int i = 0; i < enumeration->value_count(); ++i) {
98 int32_t value = enumeration->value(i)->number(); 103 int32_t value = enumeration->value(i)->number();
99 if (value < 0 || value > 0x7F) 104 if (value < 0 || value > 0x7F)
100 return false; 105 return false;
101 } 106 }
102 return true; 107 return true;
103 } 108 }
104 109
105 void Preprocess() { 110 void CollectDescriptors() {
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. 111 // Collect message descriptors in DFS order.
114 std::vector<const Descriptor*> stack; 112 std::vector<const Descriptor*> stack;
115 for (int i = 0; i < source_->message_type_count(); ++i) 113 for (int i = 0; i < source_->message_type_count(); ++i)
116 stack.push_back(source_->message_type(i)); 114 stack.push_back(source_->message_type(i));
117 115
118 while (!stack.empty()) { 116 while (!stack.empty()) {
119 const Descriptor* message = stack.back(); 117 const Descriptor* message = stack.back();
120 stack.pop_back(); 118 stack.pop_back();
121 messages_.push_back(message); 119 messages_.push_back(message);
122 for (int i = 0; i < message->nested_type_count(); ++i) { 120 for (int i = 0; i < message->nested_type_count(); ++i) {
123 stack.push_back(message->nested_type(i)); 121 stack.push_back(message->nested_type(i));
124 } 122 }
125 } 123 }
126 124
127 // Collect enums. 125 // Collect enums.
128 for (int i = 0; i < source_->enum_type_count(); ++i) 126 for (int i = 0; i < source_->enum_type_count(); ++i)
129 enums_.push_back(source_->enum_type(i)); 127 enums_.push_back(source_->enum_type(i));
130 128
131 for (const Descriptor* message : messages_) { 129 for (const Descriptor* message : messages_) {
132 for (int i = 0; i < message->enum_type_count(); ++i) { 130 for (int i = 0; i < message->enum_type_count(); ++i) {
133 enums_.push_back(message->enum_type(i)); 131 enums_.push_back(message->enum_type(i));
134 } 132 }
135 } 133 }
136 } 134 }
137 135
136 void CollectDependencies() {
137 // Public import basically means that callers only need to import this
138 // proto in order to use the stuff publicly imported by this proto.
139 for (int i = 0; i < source_->public_dependency_count(); ++i)
140 public_imports_.insert(source_->public_dependency(i));
141
142 if (source_->weak_dependency_count() > 0)
143 Abort("Weak imports are not supported.");
144
145 // Sanity check. Collect public imports (of collected imports) in DFS order.
146 // Visibilty for current proto:
147 // - all imports listed in current proto,
148 // - public imports of everything imported (recursive).
149 std::vector<const FileDescriptor*> stack;
Primiano Tucci (use gerrit) 2016/08/04 13:32:04 in general you want to name variables according to
kraynov 2016/08/04 13:42:48 It think it's okay since it's part of standard DFS
150 for (int i = 0; i < source_->dependency_count(); ++i) {
151 const FileDescriptor* proto = source_->dependency(i);
152 stack.push_back(proto);
153 if (public_imports_.find(proto) == public_imports_.end()) {
154 private_imports_.insert(proto);
155 }
156 }
157
158 while (!stack.empty()) {
159 const FileDescriptor* proto = stack.back();
160 stack.pop_back();
161 // Having imports under different packages leads to unnecessary
162 // complexity with namespaces.
163 if (proto->package() != package_)
164 Abort("Imported proto must be in the same package.");
165
166 for (int i = 0; i < proto->public_dependency_count(); ++i) {
167 stack.push_back(proto->public_dependency(i));
168 }
169 }
170
171 // Collect descriptors of messages and enums used in current proto.
172 // It will be used to generate necessary forward declarations and performed
173 // sanity check guarantees that everything lays in the same namespace.
174 for (const Descriptor* message : messages_) {
175 for (int i = 0; i < message->field_count(); ++i) {
176 const FieldDescriptor* field = message->field(i);
177
178 if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
179 if (public_imports_.find(field->message_type()->file()) ==
Primiano Tucci (use gerrit) 2016/08/04 13:32:04 .count(...) == 0
kraynov 2016/08/04 13:42:48 Acknowledged.
180 public_imports_.end()) {
181 // Avoid multiple forward declarations.
Primiano Tucci (use gerrit) 2016/08/04 13:32:04 not sure this comment adds anything useful. same b
kraynov 2016/08/04 13:42:48 Ok, will change the wording. I meant that definiti
182 referenced_messages_.insert(field->message_type());
183 }
184 } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
185 if (public_imports_.find(field->enum_type()->file()) ==
186 public_imports_.end()) {
187 // Avoid multiple forward declarations.
188 referenced_enums_.insert(field->enum_type());
189 }
190 }
191 }
192 }
193 }
194
195 void Preprocess() {
196 // Package name maps to a series of namespaces.
197 package_ = source_->package();
198 namespaces_ = Split(package_, ".");
199 full_namespace_prefix_ = "::";
200 for (const std::string& ns : namespaces_)
201 full_namespace_prefix_ += ns + "::";
202 CollectDescriptors();
203 CollectDependencies();
204 }
205
138 // Print top header, namespaces and forward declarations. 206 // Print top header, namespaces and forward declarations.
139 void GeneratePrologue() { 207 void GeneratePrologue() {
140 std::string greeting = 208 std::string greeting =
141 "// Autogenerated. DO NOT EDIT.\n" 209 "// Autogenerated. DO NOT EDIT.\n"
142 "// Protobuf compiler (protoc) has generated these stubs with\n" 210 "// Protobuf compiler (protoc) has generated these stubs with\n"
143 "// //components/tracing/tools/proto_zero_plugin.\n"; 211 "// //components/tracing/tools/proto_zero_plugin.\n";
144 std::string guard = package_ + "_" + source_->name() + "_H_"; 212 std::string guard = package_ + "_" + source_->name() + "_H_";
145 UpperString(&guard); 213 UpperString(&guard);
146 StripString(&guard, ".-", '_'); 214 StripString(&guard, ".-", '_');
147 215
148 stub_h_->Print( 216 stub_h_->Print(
149 "$greeting$\n" 217 "$greeting$\n"
150 "#ifndef $guard$\n" 218 "#ifndef $guard$\n"
151 "#define $guard$\n\n" 219 "#define $guard$\n\n"
152 "#include <stddef.h>\n" 220 "#include <stddef.h>\n"
153 "#include <stdint.h>\n\n" 221 "#include <stdint.h>\n\n"
154 "#include \"components/tracing/core/proto_zero_message.h\"\n\n", 222 "#include \"components/tracing/core/proto_zero_message.h\"\n",
155 "greeting", greeting, 223 "greeting", greeting,
156 "guard", guard); 224 "guard", guard);
157 stub_cc_->Print( 225 stub_cc_->Print(
158 "$greeting$\n" 226 "$greeting$\n"
159 "// This file intentionally left blank.\n", 227 "#include \"$name$.h\"\n",
160 "greeting", greeting); 228 "greeting", greeting,
229 "name", ProtoStubName(source_));
230
231 // Print includes for public imports.
232 for (const FileDescriptor* dependency : public_imports_) {
233 // Dependency name could contatin slashes but importing from upper-level
234 // directories is not possible anyway since build system process each
235 // proto file individually. Hence proto lookup path always equal to the
236 // directory where particular proto file is located and protoc does not
237 // allow reference to upper directory (aka ..) in import path.
238 //
239 // Laconically said:
240 // - source_->name() may never have slashes,
241 // - dependency->name() may have slashes but always reffers to inner path.
242 stub_h_->Print(
243 "#include \"$name$.h\"\n",
244 "name", ProtoStubName(dependency));
245 }
246 stub_h_->Print("\n");
247
248 // Print includes for private imports to .cc file.
249 for (const FileDescriptor* dependency : private_imports_) {
250 stub_cc_->Print(
251 "#include \"$name$.h\"\n",
252 "name", ProtoStubName(dependency));
253 }
254 stub_cc_->Print("\n");
161 255
162 // Print namespaces. 256 // Print namespaces.
163 for (const std::string& ns : namespaces_) 257 for (const std::string& ns : namespaces_) {
164 stub_h_->Print("namespace $ns$ {\n", "ns", ns); 258 stub_h_->Print("namespace $ns$ {\n", "ns", ns);
259 stub_cc_->Print("namespace $ns$ {\n", "ns", ns);
260 }
165 stub_h_->Print("\n"); 261 stub_h_->Print("\n");
262 stub_cc_->Print("\n");
263
166 // Print forward declarations. 264 // Print forward declarations.
167 for (const Descriptor* message : messages_) { 265 for (const Descriptor* message : referenced_messages_) {
168 stub_h_->Print( 266 stub_h_->Print(
169 "class $class$;\n", 267 "class $class$;\n",
170 "class", GetCppClassName(message)); 268 "class", GetCppClassName(message));
171 } 269 }
270 for (const EnumDescriptor* enumeration : referenced_enums_) {
271 stub_h_->Print(
272 "enum $class$ : int32_t;\n",
273 "class", GetCppClassName(enumeration));
274 }
172 stub_h_->Print("\n"); 275 stub_h_->Print("\n");
173 } 276 }
174 277
175 void GenerateEnumDescriptor(const EnumDescriptor* enumeration) { 278 void GenerateEnumDescriptor(const EnumDescriptor* enumeration) {
176 stub_h_->Print( 279 stub_h_->Print(
177 "enum $class$ {\n", 280 "enum $class$ : int32_t {\n",
178 "class", GetCppClassName(enumeration)); 281 "class", GetCppClassName(enumeration));
179 stub_h_->Indent(); 282 stub_h_->Indent();
180 283
181 std::string value_name_prefix; 284 std::string value_name_prefix;
182 if (enumeration->containing_type() != nullptr) 285 if (enumeration->containing_type() != nullptr)
183 value_name_prefix = GetCppClassName(enumeration) + "_"; 286 value_name_prefix = GetCppClassName(enumeration) + "_";
184 287
185 for (int i = 0; i < enumeration->value_count(); ++i) { 288 for (int i = 0; i < enumeration->value_count(); ++i) {
186 const EnumValueDescriptor* value = enumeration->value(i); 289 const EnumValueDescriptor* value = enumeration->value(i);
187 stub_h_->Print( 290 stub_h_->Print(
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 setter["appender"] = appender; 398 setter["appender"] = appender;
296 setter["cpp_type"] = cpp_type; 399 setter["cpp_type"] = cpp_type;
297 stub_h_->Print( 400 stub_h_->Print(
298 setter, 401 setter,
299 "void $action$_$name$($cpp_type$ value) {\n" 402 "void $action$_$name$($cpp_type$ value) {\n"
300 " // $appender$($id$, value);\n" 403 " // $appender$($id$, value);\n"
301 "}\n"); 404 "}\n");
302 } 405 }
303 406
304 void GenerateNestedMessageFieldDescriptor(const FieldDescriptor* field) { 407 void GenerateNestedMessageFieldDescriptor(const FieldDescriptor* field) {
408 std::string action = field->is_repeated() ? "add" : "set";
409 std::string inner_class = GetCppClassName(field->message_type());
410 std::string outer_class = GetCppClassName(field->containing_type());
411
305 stub_h_->Print( 412 stub_h_->Print(
306 "$class$* $action$_$name$() {\n" 413 "$inner_class$* $action$_$name$();\n",
307 " return BeginNestedMessage<$class$>($id$);\n" 414 "name", field->name(),
308 "}\n", 415 "action", action,
416 "inner_class", inner_class);
417 stub_cc_->Print(
418 "$inner_class$* $outer_class$::$action$_$name$() {\n"
419 " return BeginNestedMessage<$inner_class$>($id$);\n"
420 "}\n\n",
309 "id", std::to_string(field->number()), 421 "id", std::to_string(field->number()),
310 "name", field->name(), 422 "name", field->name(),
311 "action", field->is_repeated() ? "add" : "set", 423 "action", action,
312 "class", GetCppClassName(field->message_type())); 424 "inner_class", inner_class,
425 "outer_class", outer_class);
313 } 426 }
314 427
315 void GenerateMessageDescriptor(const Descriptor* message) { 428 void GenerateMessageDescriptor(const Descriptor* message) {
316 stub_h_->Print( 429 stub_h_->Print(
317 "class $name$ : public ::tracing::v2::ProtoZeroMessage {\n" 430 "class $name$ : public ::tracing::v2::ProtoZeroMessage {\n"
318 " public:\n", 431 " public:\n",
319 "name", GetCppClassName(message)); 432 "name", GetCppClassName(message));
320 stub_h_->Indent(); 433 stub_h_->Indent();
321 434
322 // Using statements for nested messages. 435 // Using statements for nested messages.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 } 479 }
367 } 480 }
368 481
369 stub_h_->Outdent(); 482 stub_h_->Outdent();
370 stub_h_->Print("};\n\n"); 483 stub_h_->Print("};\n\n");
371 } 484 }
372 485
373 void GenerateEpilogue() { 486 void GenerateEpilogue() {
374 for (unsigned i = 0; i < namespaces_.size(); ++i) { 487 for (unsigned i = 0; i < namespaces_.size(); ++i) {
375 stub_h_->Print("} // Namespace.\n"); 488 stub_h_->Print("} // Namespace.\n");
489 stub_cc_->Print("} // Namespace.\n");
376 } 490 }
377 stub_h_->Print("#endif // Include guard.\n"); 491 stub_h_->Print("#endif // Include guard.\n");
378 } 492 }
379 493
380 const FileDescriptor* const source_; 494 const FileDescriptor* const source_;
381 Printer* const stub_h_; 495 Printer* const stub_h_;
382 Printer* const stub_cc_; 496 Printer* const stub_cc_;
383 std::string error_; 497 std::string error_;
384 498
385 std::string package_; 499 std::string package_;
386 std::vector<std::string> namespaces_; 500 std::vector<std::string> namespaces_;
387 std::string full_namespace_prefix_; 501 std::string full_namespace_prefix_;
388 std::vector<const Descriptor*> messages_; 502 std::vector<const Descriptor*> messages_;
389 std::vector<const EnumDescriptor*> enums_; 503 std::vector<const EnumDescriptor*> enums_;
504
505 std::set<const FileDescriptor*> public_imports_;
506 std::set<const FileDescriptor*> private_imports_;
507 std::set<const Descriptor*> referenced_messages_;
508 std::set<const EnumDescriptor*> referenced_enums_;
390 }; 509 };
391 510
392 } // namespace 511 } // namespace
393 512
394 ProtoZeroGenerator::ProtoZeroGenerator() { 513 ProtoZeroGenerator::ProtoZeroGenerator() {
395 } 514 }
396 515
397 ProtoZeroGenerator::~ProtoZeroGenerator() { 516 ProtoZeroGenerator::~ProtoZeroGenerator() {
398 } 517 }
399 518
400 bool ProtoZeroGenerator::Generate(const FileDescriptor* file, 519 bool ProtoZeroGenerator::Generate(const FileDescriptor* file,
401 const std::string& options, 520 const std::string& options,
402 GeneratorContext* context, 521 GeneratorContext* context,
403 std::string* error) const { 522 std::string* error) const {
404 523
405 const std::string proto_stubs_name =
406 StripSuffixString(file->name(), ".proto") + ".pbzero";
407
408 const std::unique_ptr<ZeroCopyOutputStream> stub_h_file_stream( 524 const std::unique_ptr<ZeroCopyOutputStream> stub_h_file_stream(
409 context->Open(proto_stubs_name + ".h")); 525 context->Open(ProtoStubName(file) + ".h"));
410 const std::unique_ptr<ZeroCopyOutputStream> stub_cc_file_stream( 526 const std::unique_ptr<ZeroCopyOutputStream> stub_cc_file_stream(
411 context->Open(proto_stubs_name + ".cc")); 527 context->Open(ProtoStubName(file) + ".cc"));
412 528
413 // Variables are delimited by $. 529 // Variables are delimited by $.
414 Printer stub_h_printer(stub_h_file_stream.get(), '$'); 530 Printer stub_h_printer(stub_h_file_stream.get(), '$');
415 Printer stub_cc_printer(stub_cc_file_stream.get(), '$'); 531 Printer stub_cc_printer(stub_cc_file_stream.get(), '$');
416 532
417 GeneratorJob job(file, &stub_h_printer, &stub_cc_printer); 533 GeneratorJob job(file, &stub_h_printer, &stub_cc_printer);
418 if (!job.GenerateStubs()) { 534 if (!job.GenerateStubs()) {
419 *error = job.GetFirstError(); 535 *error = job.GetFirstError();
420 return false; 536 return false;
421 } 537 }
422 return true; 538 return true;
423 } 539 }
424 540
425 } // namespace proto 541 } // namespace proto
426 } // namespace tracing 542 } // namespace tracing
OLDNEW
« components/tracing/BUILD.gn ('K') | « components/tracing/test/proto_zero_generation_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698