Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |