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

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

Issue 2293073002: Tracing V2: Proto fields reflection. (Closed)
Patch Set: new one Created 4 years, 3 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 <set>
10 #include <string> 10 #include <string>
(...skipping 27 matching lines...) Expand all
38 return StripSuffixString(proto->name(), ".proto") + ".pbzero"; 38 return StripSuffixString(proto->name(), ".proto") + ".pbzero";
39 } 39 }
40 40
41 class GeneratorJob { 41 class GeneratorJob {
42 public: 42 public:
43 GeneratorJob(const FileDescriptor *file, 43 GeneratorJob(const FileDescriptor *file,
44 Printer* stub_h_printer, 44 Printer* stub_h_printer,
45 Printer* stub_cc_printer) 45 Printer* stub_cc_printer)
46 : source_(file), 46 : source_(file),
47 stub_h_(stub_h_printer), 47 stub_h_(stub_h_printer),
48 stub_cc_(stub_cc_printer) {} 48 stub_cc_(stub_cc_printer),
49 generate_reflection_(false) {}
49 50
50 bool GenerateStubs() { 51 bool GenerateStubs() {
51 Preprocess(); 52 Preprocess();
52 GeneratePrologue(); 53 GeneratePrologue();
53 for (const EnumDescriptor* enumeration: enums_) 54 for (const EnumDescriptor* enumeration: enums_)
54 GenerateEnumDescriptor(enumeration); 55 GenerateEnumDescriptor(enumeration);
55 for (const Descriptor* message : messages_) 56 for (const Descriptor* message : messages_)
56 GenerateMessageDescriptor(message); 57 GenerateMessageDescriptor(message);
57 GenerateEpilogue(); 58 GenerateEpilogue();
58 return error_.empty(); 59 return error_.empty();
59 } 60 }
60 61
61 void SetOption(const std::string& name, const std::string& value) { 62 void SetOption(const std::string& name, const std::string& value) {
62 if (name == "wrapper_namespace") { 63 if (name == "wrapper_namespace") {
63 wrapper_namespace_ = value; 64 wrapper_namespace_ = value;
65 } else if (name == "reflection") {
Primiano Tucci (use gerrit) 2016/09/01 16:18:06 ditto, less code to maintain plz :)
66 if (value == "true" || value == "1") {
67 generate_reflection_ = true;
picksi1 2016/09/01 16:38:39 There is an implication that generate_reflection d
68 } else if (value != "false" && value != "0") {
69 Abort(std::string() + "Invalid 'reflection' value '" + value + "'.");
70 }
64 } else { 71 } else {
65 Abort(std::string() + "Unknown plugin option '" + name + "'."); 72 Abort(std::string() + "Unknown plugin option '" + name + "'.");
66 } 73 }
67 } 74 }
68 75
69 // If generator fails to produce stubs for a particular proto definitions 76 // If generator fails to produce stubs for a particular proto definitions
70 // it finishes with undefined output and writes the first error occured. 77 // it finishes with undefined output and writes the first error occured.
71 const std::string& GetFirstError() const { 78 const std::string& GetFirstError() const {
72 return error_; 79 return error_;
73 } 80 }
(...skipping 20 matching lines...) Expand all
94 // prohibited but not recommended in order to avoid name collisions. 101 // prohibited but not recommended in order to avoid name collisions.
95 template <class T> 102 template <class T>
96 inline std::string GetCppClassName(const T* descriptor, bool full = false) { 103 inline std::string GetCppClassName(const T* descriptor, bool full = false) {
97 std::string name = GetDescriptorName(descriptor); 104 std::string name = GetDescriptorName(descriptor);
98 StripString(&name, ".", '_'); 105 StripString(&name, ".", '_');
99 if (full) 106 if (full)
100 name = full_namespace_prefix_ + name; 107 name = full_namespace_prefix_ + name;
101 return name; 108 return name;
102 } 109 }
103 110
111 inline std::string Capitalize(const std::string& str) {
picksi1 2016/09/01 16:38:39 Could you use Capitalize() in the SetOption functi
112 std::string copy(str);
113 copy.at(0) = toupper(copy.at(0));
114 return copy;
115 }
116
117 inline std::string GetFieldNumberConstant(const FieldDescriptor* field) {
118 std::string name = field->camelcase_name();
119 if (!name.empty()) {
120 name = std::string("k") + Capitalize(name) + "FieldNumber";
121 } else {
122 // Protoc allows fields like 'bool _ = 1'.
123 Abort("Empty field name in camel case notation.");
124 }
125 return name;
126 }
127
104 // Small enums can be written faster without involving VarInt encoder. 128 // Small enums can be written faster without involving VarInt encoder.
105 inline bool IsTinyEnumField(const FieldDescriptor* field) { 129 inline bool IsTinyEnumField(const FieldDescriptor* field) {
106 if (field->type() != FieldDescriptor::TYPE_ENUM) 130 if (field->type() != FieldDescriptor::TYPE_ENUM)
107 return false; 131 return false;
108 const EnumDescriptor* enumeration = field->enum_type(); 132 const EnumDescriptor* enumeration = field->enum_type();
109 133
110 for (int i = 0; i < enumeration->value_count(); ++i) { 134 for (int i = 0; i < enumeration->value_count(); ++i) {
111 int32_t value = enumeration->value(i)->number(); 135 int32_t value = enumeration->value(i)->number();
112 if (value < 0 || value > 0x7F) 136 if (value < 0 || value > 0x7F)
113 return false; 137 return false;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 stub_h_->Print("\n"); 280 stub_h_->Print("\n");
257 281
258 // Print includes for private imports to .cc file. 282 // Print includes for private imports to .cc file.
259 for (const FileDescriptor* dependency : private_imports_) { 283 for (const FileDescriptor* dependency : private_imports_) {
260 stub_cc_->Print( 284 stub_cc_->Print(
261 "#include \"$name$.h\"\n", 285 "#include \"$name$.h\"\n",
262 "name", ProtoStubName(dependency)); 286 "name", ProtoStubName(dependency));
263 } 287 }
264 stub_cc_->Print("\n"); 288 stub_cc_->Print("\n");
265 289
290 if (generate_reflection_ && messages_.size() > 0)
291 stub_cc_->Print(
292 "namespace {\n"
293 " static const ::tracing::v2::proto::ProtoFieldDescriptor "
294 "__invalid_field = {\"\", "
Primiano Tucci (use gerrit) 2016/09/01 16:18:06 just calling kInvalidField should be enough and fi
295 "::tracing::v2::proto::ProtoFieldDescriptor::Type::TYPE_INVALID, "
296 "0, false};\n"
297 "}\n\n");
298
266 // Print namespaces. 299 // Print namespaces.
267 for (const std::string& ns : namespaces_) { 300 for (const std::string& ns : namespaces_) {
268 stub_h_->Print("namespace $ns$ {\n", "ns", ns); 301 stub_h_->Print("namespace $ns$ {\n", "ns", ns);
269 stub_cc_->Print("namespace $ns$ {\n", "ns", ns); 302 stub_cc_->Print("namespace $ns$ {\n", "ns", ns);
270 } 303 }
271 stub_h_->Print("\n"); 304 stub_h_->Print("\n");
272 stub_cc_->Print("\n"); 305 stub_cc_->Print("\n");
273 306
274 // Print forward declarations. 307 // Print forward declarations.
275 for (const Descriptor* message : referenced_messages_) { 308 for (const Descriptor* message : referenced_messages_) {
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 "$inner_class$* $outer_class$::$action$_$name$() {\n" 461 "$inner_class$* $outer_class$::$action$_$name$() {\n"
429 " return BeginNestedMessage<$inner_class$>($id$);\n" 462 " return BeginNestedMessage<$inner_class$>($id$);\n"
430 "}\n\n", 463 "}\n\n",
431 "id", std::to_string(field->number()), 464 "id", std::to_string(field->number()),
432 "name", field->name(), 465 "name", field->name(),
433 "action", action, 466 "action", action,
434 "inner_class", inner_class, 467 "inner_class", inner_class,
435 "outer_class", outer_class); 468 "outer_class", outer_class);
436 } 469 }
437 470
471 void GenerateReflectionHelpers(const Descriptor* message) {
472 // Field numbers.
473 if (message->field_count() > 0) {
picksi1 2016/09/01 16:38:39 There are a number of places where the code has th
474 stub_h_->Print("enum : int32_t {\n");
475 stub_h_->Indent();
476
477 for (int i = 0; i < message->field_count(); ++i) {
478 const FieldDescriptor* field = message->field(i);
479 stub_h_->Print(
480 "$name$ = $id$,\n",
481 "name", GetFieldNumberConstant(field),
482 "id", std::to_string(field->number()));
483 }
484 stub_h_->Outdent();
485 stub_h_->Print("};\n");
486 }
487
488 // Fields reflection.
489 stub_h_->Print(
490 "static const ::tracing::v2::proto::ProtoFieldDescriptor* "
491 "GetFieldDescriptor(uint32_t field_id);\n");
492
493 std::string class_name = GetCppClassName(message);
494 if (message->field_count() > 0) {
495 stub_cc_->Print(
496 "static const ::tracing::v2::proto::ProtoFieldDescriptor "
497 "__fields_$class$[] = {\n",
Primiano Tucci (use gerrit) 2016/09/01 16:18:06 ditto, just kFields... as this is a non exported s
498 "class", class_name);
499 stub_cc_->Indent();
500 for (int i = 0; i < message->field_count(); ++i) {
501 const FieldDescriptor* field = message->field(i);
502 // Caveats:
503 // There is assumption that field type enums (protoc and ProtoZero) have
504 // same numbers for corresponding types. Hence, there is a test.
Primiano Tucci (use gerrit) 2016/09/01 16:18:06 s/Hence, there is a test./This is covered by TEST_
505 stub_cc_->Print(
506 "{\"$name$\", static_cast"
507 "<::tracing::v2::proto::ProtoFieldDescriptor::Type>($type$), "
508 "$number$, $is_repeated$},\n",
509 "name", field->name(),
510 "type", std::to_string(static_cast<int>(field->type())),
511 "number", std::to_string(field->number()),
512 "is_repeated", std::to_string(field->is_repeated()));
513 }
514 stub_cc_->Outdent();
515 stub_cc_->Print("};\n\n");
516 }
517
518 stub_cc_->Print(
519 "const ::tracing::v2::proto::ProtoFieldDescriptor* "
520 "$class$::GetFieldDescriptor(uint32_t field_id) {\n",
521 "class", class_name);
522 stub_cc_->Indent();
523 if (message->field_count() > 0) {
524 stub_cc_->Print("switch (field_id) {\n");
525 stub_cc_->Indent();
526 for (int i = 0; i < message->field_count(); ++i) {
527 stub_cc_->Print(
528 "case $field$:\n"
529 " return &__fields_$class$[$id$];\n",
530 "class", class_name,
531 "field", GetFieldNumberConstant(message->field(i)),
532 "id", std::to_string(i));
533 }
534 stub_cc_->Print(
535 "default:\n"
536 " return &__invalid_field;\n");
537 stub_cc_->Outdent();
538 stub_cc_->Print("}\n");
539 } else {
540 stub_cc_->Print("return &__invalid_field;\n");
541 }
542 stub_cc_->Outdent();
543 stub_cc_->Print("}\n\n");
544 }
545
438 void GenerateMessageDescriptor(const Descriptor* message) { 546 void GenerateMessageDescriptor(const Descriptor* message) {
439 stub_h_->Print( 547 stub_h_->Print(
440 "class $name$ : public ::tracing::v2::ProtoZeroMessage {\n" 548 "class $name$ : public ::tracing::v2::ProtoZeroMessage {\n"
441 " public:\n", 549 " public:\n",
442 "name", GetCppClassName(message)); 550 "name", GetCppClassName(message));
443 stub_h_->Indent(); 551 stub_h_->Indent();
444 552
553 if (generate_reflection_)
554 GenerateReflectionHelpers(message);
picksi1 2016/09/01 16:38:39 Is this function correctly named GenerateReflectio
555
445 // Using statements for nested messages. 556 // Using statements for nested messages.
446 for (int i = 0; i < message->nested_type_count(); ++i) { 557 for (int i = 0; i < message->nested_type_count(); ++i) {
447 const Descriptor* nested_message = message->nested_type(i); 558 const Descriptor* nested_message = message->nested_type(i);
448 stub_h_->Print( 559 stub_h_->Print(
449 "using $local_name$ = $global_name$;\n", 560 "using $local_name$ = $global_name$;\n",
450 "local_name", nested_message->name(), 561 "local_name", nested_message->name(),
451 "global_name", GetCppClassName(nested_message, true)); 562 "global_name", GetCppClassName(nested_message, true));
452 } 563 }
453 564
454 // Using statements for nested enums. 565 // Using statements for nested enums.
(...skipping 13 matching lines...) Expand all
468 for (int j = 0; j < nested_enum->value_count(); ++j) { 579 for (int j = 0; j < nested_enum->value_count(); ++j) {
469 const EnumValueDescriptor* value = nested_enum->value(j); 580 const EnumValueDescriptor* value = nested_enum->value(j);
470 stub_h_->Print( 581 stub_h_->Print(
471 "static const $class$ $name$ = $full_name$;\n", 582 "static const $class$ $name$ = $full_name$;\n",
472 "class", nested_enum->name(), 583 "class", nested_enum->name(),
473 "name", value->name(), 584 "name", value->name(),
474 "full_name", value_name_prefix + value->name()); 585 "full_name", value_name_prefix + value->name());
475 } 586 }
476 } 587 }
477 588
478 // Field numbers.
479 if (message->field_count() > 0) {
480 stub_h_->Print("enum : int32_t {\n");
481 stub_h_->Indent();
482
483 for (int i = 0; i < message->field_count(); ++i) {
484 const FieldDescriptor* field = message->field(i);
485 std::string name = field->camelcase_name();
486 if (!name.empty()) {
487 name.at(0) = toupper(name.at(0));
488 } else {
489 // Protoc allows fields like 'bool _ = 1'.
490 Abort("Empty field name in camel case notation.");
491 }
492
493 stub_h_->Print(
494 "k$name$FieldNumber = $id$,\n",
495 "name", name,
496 "id", std::to_string(field->number()));
497 }
498 stub_h_->Outdent();
499 stub_h_->Print("};\n");
500 }
501
502 // Field descriptors. 589 // Field descriptors.
503 for (int i = 0; i < message->field_count(); ++i) { 590 for (int i = 0; i < message->field_count(); ++i) {
504 const FieldDescriptor* field = message->field(i); 591 const FieldDescriptor* field = message->field(i);
505 if (field->is_packed()) { 592 if (field->is_packed()) {
506 Abort("Packed repeated fields are not supported."); 593 Abort("Packed repeated fields are not supported.");
507 return; 594 return;
508 } 595 }
509 if (field->type() != FieldDescriptor::TYPE_MESSAGE) { 596 if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
510 GenerateSimpleFieldDescriptor(field); 597 GenerateSimpleFieldDescriptor(field);
511 } else { 598 } else {
(...skipping 11 matching lines...) Expand all
523 stub_cc_->Print("} // Namespace.\n"); 610 stub_cc_->Print("} // Namespace.\n");
524 } 611 }
525 stub_h_->Print("#endif // Include guard.\n"); 612 stub_h_->Print("#endif // Include guard.\n");
526 } 613 }
527 614
528 const FileDescriptor* const source_; 615 const FileDescriptor* const source_;
529 Printer* const stub_h_; 616 Printer* const stub_h_;
530 Printer* const stub_cc_; 617 Printer* const stub_cc_;
531 std::string error_; 618 std::string error_;
532 619
620 bool generate_reflection_;
533 std::string package_; 621 std::string package_;
534 std::string wrapper_namespace_; 622 std::string wrapper_namespace_;
535 std::vector<std::string> namespaces_; 623 std::vector<std::string> namespaces_;
536 std::string full_namespace_prefix_; 624 std::string full_namespace_prefix_;
537 std::vector<const Descriptor*> messages_; 625 std::vector<const Descriptor*> messages_;
538 std::vector<const EnumDescriptor*> enums_; 626 std::vector<const EnumDescriptor*> enums_;
539 627
540 std::set<const FileDescriptor*> public_imports_; 628 std::set<const FileDescriptor*> public_imports_;
541 std::set<const FileDescriptor*> private_imports_; 629 std::set<const FileDescriptor*> private_imports_;
542 std::set<const Descriptor*> referenced_messages_; 630 std::set<const Descriptor*> referenced_messages_;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 662
575 if (!job.GenerateStubs()) { 663 if (!job.GenerateStubs()) {
576 *error = job.GetFirstError(); 664 *error = job.GetFirstError();
577 return false; 665 return false;
578 } 666 }
579 return true; 667 return true;
580 } 668 }
581 669
582 } // namespace proto 670 } // namespace proto
583 } // namespace tracing 671 } // namespace tracing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698