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 25 matching lines...) Expand all Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |