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

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

Issue 2293073002: Tracing V2: Proto fields reflection. (Closed)
Patch Set: nit 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
« no previous file with comments | « components/tracing/test/proto_zero_generation_unittest.cc ('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 <map>
8 #include <memory> 8 #include <memory>
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
(...skipping 25 matching lines...) Expand all
36 36
37 inline std::string ProtoStubName(const FileDescriptor* proto) { 37 inline std::string ProtoStubName(const FileDescriptor* proto) {
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), stub_h_(stub_h_printer), stub_cc_(stub_cc_printer) {
47 stub_h_(stub_h_printer), 47 }
48 stub_cc_(stub_cc_printer) {}
49 48
50 bool GenerateStubs() { 49 bool GenerateStubs() {
51 Preprocess(); 50 Preprocess();
52 GeneratePrologue(); 51 GeneratePrologue();
53 for (const EnumDescriptor* enumeration: enums_) 52 for (const EnumDescriptor* enumeration: enums_)
54 GenerateEnumDescriptor(enumeration); 53 GenerateEnumDescriptor(enumeration);
55 for (const Descriptor* message : messages_) 54 for (const Descriptor* message : messages_)
56 GenerateMessageDescriptor(message); 55 GenerateMessageDescriptor(message);
57 GenerateEpilogue(); 56 GenerateEpilogue();
58 return error_.empty(); 57 return error_.empty();
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 // prohibited but not recommended in order to avoid name collisions. 93 // prohibited but not recommended in order to avoid name collisions.
95 template <class T> 94 template <class T>
96 inline std::string GetCppClassName(const T* descriptor, bool full = false) { 95 inline std::string GetCppClassName(const T* descriptor, bool full = false) {
97 std::string name = GetDescriptorName(descriptor); 96 std::string name = GetDescriptorName(descriptor);
98 StripString(&name, ".", '_'); 97 StripString(&name, ".", '_');
99 if (full) 98 if (full)
100 name = full_namespace_prefix_ + name; 99 name = full_namespace_prefix_ + name;
101 return name; 100 return name;
102 } 101 }
103 102
103 inline std::string GetFieldNumberConstant(const FieldDescriptor* field) {
104 std::string name = field->camelcase_name();
105 if (!name.empty()) {
106 name.at(0) = toupper(name.at(0));
107 name = std::string("k") + name + "FieldNumber";
Primiano Tucci (use gerrit) 2016/09/02 16:49:51 you can avoid std::string and just "k" here.
108 } else {
109 // Protoc allows fields like 'bool _ = 1'.
110 Abort("Empty field name in camel case notation.");
111 }
112 return name;
113 }
114
104 // Small enums can be written faster without involving VarInt encoder. 115 // Small enums can be written faster without involving VarInt encoder.
105 inline bool IsTinyEnumField(const FieldDescriptor* field) { 116 inline bool IsTinyEnumField(const FieldDescriptor* field) {
106 if (field->type() != FieldDescriptor::TYPE_ENUM) 117 if (field->type() != FieldDescriptor::TYPE_ENUM)
107 return false; 118 return false;
108 const EnumDescriptor* enumeration = field->enum_type(); 119 const EnumDescriptor* enumeration = field->enum_type();
109 120
110 for (int i = 0; i < enumeration->value_count(); ++i) { 121 for (int i = 0; i < enumeration->value_count(); ++i) {
111 int32_t value = enumeration->value(i)->number(); 122 int32_t value = enumeration->value(i)->number();
112 if (value < 0 || value > 0x7F) 123 if (value < 0 || value > 0x7F)
113 return false; 124 return false;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 stub_h_->Print("\n"); 267 stub_h_->Print("\n");
257 268
258 // Print includes for private imports to .cc file. 269 // Print includes for private imports to .cc file.
259 for (const FileDescriptor* dependency : private_imports_) { 270 for (const FileDescriptor* dependency : private_imports_) {
260 stub_cc_->Print( 271 stub_cc_->Print(
261 "#include \"$name$.h\"\n", 272 "#include \"$name$.h\"\n",
262 "name", ProtoStubName(dependency)); 273 "name", ProtoStubName(dependency));
263 } 274 }
264 stub_cc_->Print("\n"); 275 stub_cc_->Print("\n");
265 276
277 if (messages_.size() > 0) {
278 stub_cc_->Print(
279 "namespace {\n"
280 " static const ::tracing::v2::proto::ProtoFieldDescriptor "
281 "kInvalidField = {\"\", "
282 "::tracing::v2::proto::ProtoFieldDescriptor::Type::TYPE_INVALID, "
283 "0, false};\n"
284 "}\n\n");
285 }
286
266 // Print namespaces. 287 // Print namespaces.
267 for (const std::string& ns : namespaces_) { 288 for (const std::string& ns : namespaces_) {
268 stub_h_->Print("namespace $ns$ {\n", "ns", ns); 289 stub_h_->Print("namespace $ns$ {\n", "ns", ns);
269 stub_cc_->Print("namespace $ns$ {\n", "ns", ns); 290 stub_cc_->Print("namespace $ns$ {\n", "ns", ns);
270 } 291 }
271 stub_h_->Print("\n"); 292 stub_h_->Print("\n");
272 stub_cc_->Print("\n"); 293 stub_cc_->Print("\n");
273 294
274 // Print forward declarations. 295 // Print forward declarations.
275 for (const Descriptor* message : referenced_messages_) { 296 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" 449 "$inner_class$* $outer_class$::$action$_$name$() {\n"
429 " return BeginNestedMessage<$inner_class$>($id$);\n" 450 " return BeginNestedMessage<$inner_class$>($id$);\n"
430 "}\n\n", 451 "}\n\n",
431 "id", std::to_string(field->number()), 452 "id", std::to_string(field->number()),
432 "name", field->name(), 453 "name", field->name(),
433 "action", action, 454 "action", action,
434 "inner_class", inner_class, 455 "inner_class", inner_class,
435 "outer_class", outer_class); 456 "outer_class", outer_class);
436 } 457 }
437 458
459 // TODO(kraynov): Implement reflection for enums.
Primiano Tucci (use gerrit) 2016/09/02 16:49:51 Not sure we need this. I'd remove this todo. If we
460 void GenerateReflectionForMessageFields(const Descriptor* message) {
461 const bool has_fields = (message->field_count() > 0);
462
463 // Field number constants.
464 if (has_fields) {
465 stub_h_->Print("enum : int32_t {\n");
466 stub_h_->Indent();
467
468 for (int i = 0; i < message->field_count(); ++i) {
469 const FieldDescriptor* field = message->field(i);
470 stub_h_->Print(
471 "$name$ = $id$,\n",
472 "name", GetFieldNumberConstant(field),
473 "id", std::to_string(field->number()));
474 }
475 stub_h_->Outdent();
476 stub_h_->Print("};\n");
477 }
478
479 // Fields reflection table.
480 stub_h_->Print(
481 "static const ::tracing::v2::proto::ProtoFieldDescriptor* "
482 "GetFieldDescriptor(uint32_t field_id);\n");
483
484 std::string class_name = GetCppClassName(message);
485 if (has_fields) {
486 stub_cc_->Print(
487 "static const ::tracing::v2::proto::ProtoFieldDescriptor "
488 "kFields_$class$[] = {\n",
489 "class", class_name);
490 stub_cc_->Indent();
491 for (int i = 0; i < message->field_count(); ++i) {
492 const FieldDescriptor* field = message->field(i);
493 std::string type_const = "TYPE_";
494 type_const += FieldDescriptor::TypeName(field->type());
Primiano Tucci (use gerrit) 2016/09/02 16:49:51 maybe you can do this in one line and to: type_con
495 UpperString(&type_const);
496 stub_cc_->Print(
497 "{\"$name$\", "
498 "::tracing::v2::proto::ProtoFieldDescriptor::Type::$type$, "
499 "$number$, $is_repeated$},\n",
500 "name", field->name(),
501 "type", type_const,
502 "number", std::to_string(field->number()),
503 "is_repeated", std::to_string(field->is_repeated()));
504 }
505 stub_cc_->Outdent();
506 stub_cc_->Print("};\n\n");
507 }
508
509 // Fields reflection getter.
510 stub_cc_->Print(
511 "const ::tracing::v2::proto::ProtoFieldDescriptor* "
512 "$class$::GetFieldDescriptor(uint32_t field_id) {\n",
513 "class", class_name);
514 stub_cc_->Indent();
515 if (message->field_count() > 0) {
516 stub_cc_->Print("switch (field_id) {\n");
517 stub_cc_->Indent();
518 for (int i = 0; i < message->field_count(); ++i) {
519 stub_cc_->Print(
520 "case $field$:\n"
521 " return &kFields_$class$[$id$];\n",
522 "class", class_name,
523 "field", GetFieldNumberConstant(message->field(i)),
524 "id", std::to_string(i));
525 }
526 stub_cc_->Print(
527 "default:\n"
528 " return &kInvalidField;\n");
529 stub_cc_->Outdent();
530 stub_cc_->Print("}\n");
531 } else {
532 stub_cc_->Print("return &kInvalidField;\n");
533 }
534 stub_cc_->Outdent();
535 stub_cc_->Print("}\n\n");
536 }
537
438 void GenerateMessageDescriptor(const Descriptor* message) { 538 void GenerateMessageDescriptor(const Descriptor* message) {
439 stub_h_->Print( 539 stub_h_->Print(
440 "class $name$ : public ::tracing::v2::ProtoZeroMessage {\n" 540 "class $name$ : public ::tracing::v2::ProtoZeroMessage {\n"
441 " public:\n", 541 " public:\n",
442 "name", GetCppClassName(message)); 542 "name", GetCppClassName(message));
443 stub_h_->Indent(); 543 stub_h_->Indent();
444 544
545 GenerateReflectionForMessageFields(message);
546
445 // Using statements for nested messages. 547 // Using statements for nested messages.
446 for (int i = 0; i < message->nested_type_count(); ++i) { 548 for (int i = 0; i < message->nested_type_count(); ++i) {
447 const Descriptor* nested_message = message->nested_type(i); 549 const Descriptor* nested_message = message->nested_type(i);
448 stub_h_->Print( 550 stub_h_->Print(
449 "using $local_name$ = $global_name$;\n", 551 "using $local_name$ = $global_name$;\n",
450 "local_name", nested_message->name(), 552 "local_name", nested_message->name(),
451 "global_name", GetCppClassName(nested_message, true)); 553 "global_name", GetCppClassName(nested_message, true));
452 } 554 }
453 555
454 // Using statements for nested enums. 556 // Using statements for nested enums.
(...skipping 13 matching lines...) Expand all
468 for (int j = 0; j < nested_enum->value_count(); ++j) { 570 for (int j = 0; j < nested_enum->value_count(); ++j) {
469 const EnumValueDescriptor* value = nested_enum->value(j); 571 const EnumValueDescriptor* value = nested_enum->value(j);
470 stub_h_->Print( 572 stub_h_->Print(
471 "static const $class$ $name$ = $full_name$;\n", 573 "static const $class$ $name$ = $full_name$;\n",
472 "class", nested_enum->name(), 574 "class", nested_enum->name(),
473 "name", value->name(), 575 "name", value->name(),
474 "full_name", value_name_prefix + value->name()); 576 "full_name", value_name_prefix + value->name());
475 } 577 }
476 } 578 }
477 579
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. 580 // Field descriptors.
503 for (int i = 0; i < message->field_count(); ++i) { 581 for (int i = 0; i < message->field_count(); ++i) {
504 const FieldDescriptor* field = message->field(i); 582 const FieldDescriptor* field = message->field(i);
505 if (field->is_packed()) { 583 if (field->is_packed()) {
506 Abort("Packed repeated fields are not supported."); 584 Abort("Packed repeated fields are not supported.");
507 return; 585 return;
508 } 586 }
509 if (field->type() != FieldDescriptor::TYPE_MESSAGE) { 587 if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
510 GenerateSimpleFieldDescriptor(field); 588 GenerateSimpleFieldDescriptor(field);
511 } else { 589 } else {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 652
575 if (!job.GenerateStubs()) { 653 if (!job.GenerateStubs()) {
576 *error = job.GetFirstError(); 654 *error = job.GetFirstError();
577 return false; 655 return false;
578 } 656 }
579 return true; 657 return true;
580 } 658 }
581 659
582 } // namespace proto 660 } // namespace proto
583 } // namespace tracing 661 } // namespace tracing
OLDNEW
« no previous file with comments | « 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