diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/tools/protoc/plugins/cpp_styleguide/cpp_styleguide.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/tools/protoc/plugins/cpp_styleguide/cpp_styleguide.cpp')
-rw-r--r-- | contrib/tools/protoc/plugins/cpp_styleguide/cpp_styleguide.cpp | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/contrib/tools/protoc/plugins/cpp_styleguide/cpp_styleguide.cpp b/contrib/tools/protoc/plugins/cpp_styleguide/cpp_styleguide.cpp new file mode 100644 index 00000000000..cd96aa05657 --- /dev/null +++ b/contrib/tools/protoc/plugins/cpp_styleguide/cpp_styleguide.cpp @@ -0,0 +1,1021 @@ +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/strutil.h> + +#include "cpp_styleguide.h" +#include <util/stream/output.h> + +namespace NProtobuf { +namespace NCompiler { +namespace NPlugins { + + using namespace google::protobuf; + using namespace google::protobuf::compiler; + using namespace google::protobuf::compiler::cpp; + + typedef std::map<TProtoStringType, TProtoStringType> TVariables; + + bool GenerateYaStyle(const FileDescriptor* fileDescriptor) { + const auto& extension = fileDescriptor->FindExtensionByName("GenerateYaStyle"); + return extension; + } + + bool GenerateYaStyle(const FieldDescriptor* descriptor) { + const auto& fileDescriptor = descriptor->file(); + return GenerateYaStyle(fileDescriptor); + } + + + void SetCommonFieldVariables(const FieldDescriptor* descriptor, TVariables* variables) { + const auto& name = descriptor->name(); + if (GenerateYaStyle(descriptor)) + (*variables)["rname"] = UnderscoresToCamelCase(name, true); + else + (*variables)["rname"] = name; + (*variables)["name"] = FieldName(descriptor); + } + + TProtoStringType HeaderFileName(const FileDescriptor* file) { + TProtoStringType basename = compiler::StripProto(file->name()); + return basename.append(".pb.h"); + } + + TProtoStringType SourceFileName(const FileDescriptor* file) { + TProtoStringType basename = compiler::StripProto(file->name()); + return basename.append(".pb.cc"); + } + + bool IsLiteRuntimeMessage(const Descriptor* desc) { + return desc->file() != NULL && desc->file()->options().optimize_for() == google::protobuf::FileOptions::LITE_RUNTIME; + } + + bool IsAutogeneratedNestedType(const Descriptor* desc) { + return desc->options().map_entry(); + } + + class TFieldExtGenerator { + public: + TFieldExtGenerator(const FieldDescriptor* field) + : Field_(field) + { + SetCommonFieldVariables(Field_, &Variables_); + } + + virtual ~TFieldExtGenerator() { + } + + virtual void GenerateAccessorDeclarations(io::Printer* printer) = 0; + virtual void GenerateJSONPrinting(io::Printer* printer) = 0; + + protected: + void GenerateRepeatedJSONPrinting(io::Printer* printer, const char* itemPrinter) { + printer->Print("out << '[';\n"); + printer->Print("{\n"); + printer->Indent(); + printer->Print("const char* separator = \"\";\n"); + printer->Print(Variables_, "for (size_t _index = 0; _index < $rname$Size(); ++_index) {\n"); + printer->Indent(); + printer->Print("out << separator;\n"); + printer->Print(Variables_, itemPrinter); + printer->Print(";\n"); + printer->Print("separator = \",\";\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print("out << ']';\n"); + } + + protected: + const FieldDescriptor* Field_; + TVariables Variables_; + }; + + + class TMessageFieldExtGenerator: public TFieldExtGenerator { + public: + TMessageFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + { + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + Variables_["type"] = QualifiedClassName(Field_->message_type()); + + printer->Print(Variables_, + "inline const $type$& Get$rname$() const { return $name$(); }\n" + "inline $type$* Mutable$rname$() { return mutable_$name$(); }\n"); + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline const $type$& Get$RName$() const { return $name$(); }\n" + "inline $type$* Mutable$RName$() { return mutable_$name$(); }\n"); + } + + void GenerateJSONPrinting(io::Printer* printer) override { + printer->Print(Variables_, "Get$rname$().PrintJSON(out);\n"); + } + }; + + class TMapFieldExtGenerator: public TFieldExtGenerator { + public: + TMapFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + , Key_(field->message_type()->FindFieldByName("key")) + , Val_(field->message_type()->FindFieldByName("value")) + { + Variables_["key_cpp"] = PrimitiveTypeName(Key_->cpp_type()); + + switch (Val_->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + Variables_["val_cpp"] = QualifiedClassName(Val_->message_type()); + break; + case FieldDescriptor::CPPTYPE_ENUM: + Variables_["val_cpp"] = ClassName(Val_->enum_type(), true); + break; + default: + Variables_["val_cpp"] = PrimitiveTypeName(Val_->cpp_type()); + } + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + printer->Print(Variables_, + "inline const ::google::protobuf::Map<$key_cpp$, $val_cpp$>& Get$rname$() const { return $name$(); }\n" + "inline ::google::protobuf::Map<$key_cpp$, $val_cpp$>* Mutable$rname$() { return mutable_$name$(); }\n"); + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline const ::google::protobuf::Map<$key_cpp$, $val_cpp$>& Get$RName$() const { return $name$(); }\n" + "inline ::google::protobuf::Map<$key_cpp$, $val_cpp$>* Mutable$RName$() { return mutable_$name$(); }\n"); + } + + void GenerateKeyValuePrinting(io::Printer* printer, const char* scopeName, bool isKey) { + const FieldDescriptor* desc = isKey ? Key_ : Val_; + + switch(desc->cpp_type()) { + case FieldDescriptor::CPPTYPE_STRING: + printer->Print(TString::Join("::google::protobuf::io::PrintJSONString(out, ", scopeName , ");\n").data()); + break; + case FieldDescriptor::CPPTYPE_ENUM: + printer->Print(TString::Join("out << int(", scopeName, ");\n").data()); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + printer->Print(TString::Join(scopeName, ".PrintJSON(out);\n").data()); + break; + default: + if (isKey) { + printer->Print(TString::Join("out << '\"' << ", scopeName, " << '\"';\n").data()); + } else { + printer->Print(TString::Join("out << ", scopeName, ";\n").data()); + } + } + } + + void GenerateJSONPrinting(io::Printer* printer) { + printer->Print(Variables_, + "out << '{';\n" + "const ::google::protobuf::Map<$key_cpp$, $val_cpp$>& map = Get$rname$();\n" + "for (auto it = map.begin(); it != map.end(); ++it) {\n" + ); + printer->Indent(); + printer->Print("if (it != map.begin()) { out << ','; }\n"); + + GenerateKeyValuePrinting(printer, "it->first", true); + printer->Print("out << ':';\n"); + GenerateKeyValuePrinting(printer, "it->second", false); + + printer->Outdent(); + printer->Print("}\n"); + printer->Print("out << '}';\n"); + } + + private: + const FieldDescriptor* Key_; + const FieldDescriptor* Val_; + }; + + class TRepeatedMessageFieldExtGenerator: public TFieldExtGenerator { + public: + TRepeatedMessageFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + { + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + Variables_["type"] = QualifiedClassName(Field_->message_type()); + + printer->Print(Variables_, + "inline const $type$& Get$rname$(size_t _index) const {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return $name$(int(_index)); }\n" + "inline $type$* Mutable$rname$(size_t _index) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return mutable_$name$(int(_index)); }\n" + "inline $type$* Add$rname$() { return add_$name$(); }\n" + "inline const $type$& get_idx_$name$(int _index) const { return $name$(_index); }\n" + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " get_arr_$name$() const { return $name$(); }\n" + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " Get$rname$() const { return $name$(); }\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + " Mutable$rname$() { return mutable_$name$(); }\n"); + + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline const $type$& Get$RName$(size_t _index) const {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return $name$(int(_index)); }\n" + "inline $type$* Mutable$RName$(size_t _index) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return mutable_$name$(int(_index)); }\n" + "inline $type$* Add$RName$() { return add_$name$(); }\n" + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " Get$RName$() const { return $name$(); }\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + " Mutable$RName$() { return mutable_$name$(); }\n" + ); + } + + void GenerateJSONPrinting(io::Printer* printer) override { + GenerateRepeatedJSONPrinting(printer, "Get$rname$(_index).PrintJSON(out)"); + } + }; + + class TStringFieldExtGenerator: public TFieldExtGenerator { + public: + TStringFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + { + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + Variables_["pointer_type"] = Field_->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; + + if (Field_->options().ctype() != FieldOptions::STRING) { + printer->Outdent(); + printer->Print( + " private:\n" + " // Hidden due to unknown ctype option.\n"); + printer->Indent(); + } + + printer->Print(Variables_, + "inline const TProtoStringType& Get$rname$() const { return $name$(); }\n" + "inline void Set$rname$(const TProtoStringType& value) { set_$name$(value); }\n" + "inline void Set$rname$(TProtoStringType&& value) { set_$name$(std::move(value)); }\n" + "inline void Set$rname$(const char* value) { set_$name$(value); }\n" + "inline void Set$rname$(const $pointer_type$* value, size_t size) { set_$name$(value, size); }\n" + "inline TProtoStringType* Mutable$rname$() { return mutable_$name$(); }\n"); + + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline const TProtoStringType& Get$RName$() const { return $name$(); }\n" + "inline void Set$RName$(const TProtoStringType& value) { set_$name$(value); }\n" + "inline void Set$RName$(TProtoStringType&& value) { set_$name$(std::move(value)); }\n" + "inline void Set$RName$(const char* value) { set_$name$(value); }\n" + "inline void Set$RName$(const $pointer_type$* value, size_t size) { set_$name$(value, size); }\n" + "inline TProtoStringType* Mutable$RName$() { return mutable_$name$(); }\n" + ); + + if (Field_->options().ctype() != FieldOptions::STRING) { + printer->Outdent(); + printer->Print(" public:\n"); + printer->Indent(); + } + + } + + void GenerateJSONPrinting(io::Printer* printer) override { + printer->Print(Variables_, "::google::protobuf::io::PrintJSONString(out, Get$rname$());\n"); + } + }; + + class TRepeatedStringFieldExtGenerator: public TFieldExtGenerator { + public: + TRepeatedStringFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + { + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + Variables_["pointer_type"] = Field_->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; + + if (Field_->options().ctype() != FieldOptions::STRING) { + printer->Outdent(); + printer->Print( + " private:\n" + " // Hidden due to unknown ctype option.\n"); + printer->Indent(); + } + + printer->Print(Variables_, + "inline const TProtoStringType& Get$rname$(size_t _index) const {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return $name$(_index); }\n" + "inline TProtoStringType* Mutable$rname$(size_t _index) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return mutable_$name$(_index); }\n" + "inline void Set$rname$(size_t _index, const TProtoStringType& value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value); }\n" + "inline void Set$rname$(size_t _index, TProtoStringType&& value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, std::move(value)); }\n" + "inline void Set$rname$(size_t _index, const char* value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value); }\n" + "inline void Set$rname$(size_t _index, const $pointer_type$* value, size_t size) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value, size); }\n" + "inline TProtoStringType* Add$rname$() { return add_$name$(); }\n" + "inline void Add$rname$(const TProtoStringType& value) { add_$name$(value); }\n" + "inline void Add$rname$(TProtoStringType&& value) { add_$name$(std::move(value)); }\n" + "inline void Add$rname$(const char* value) { add_$name$(value); }\n" + "inline void Add$rname$(const $pointer_type$* value, size_t size) { add_$name$(value, size); }\n" + "inline const TProtoStringType& get_idx_$name$(int _index) const { return $name$(_index); }\n" + "inline const ::google::protobuf::RepeatedPtrField<TProtoStringType>& get_arr_$name$() const" + "{ return $name$(); }\n" + "inline const ::google::protobuf::RepeatedPtrField<TProtoStringType>& Get$rname$() const" + "{ return $name$(); }\n" + "inline ::google::protobuf::RepeatedPtrField<TProtoStringType>* Mutable$rname$()" + "{ return mutable_$name$(); }\n"); + + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline const TProtoStringType& Get$RName$(size_t _index) const {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return $name$(_index); }\n" + "inline TProtoStringType* Mutable$RName$(size_t _index) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return mutable_$name$(_index); }\n" + "inline void Set$RName$(size_t _index, const TProtoStringType& value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value); }\n" + "inline void Set$RName$(size_t _index, TProtoStringType&& value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, std::move(value)); }\n" + "inline void Set$RName$(size_t _index, const char* value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value); }\n" + "inline void Set$RName$(size_t _index, const $pointer_type$* value, size_t size) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value, size); }\n" + "inline TProtoStringType* Add$RName$() { return add_$name$(); }\n" + "inline void Add$RName$(const TProtoStringType& value) { add_$name$(value); }\n" + "inline void Add$RName$(TProtoStringType&& value) { add_$name$(std::move(value)); }\n" + "inline void Add$RName$(const char* value) { add_$name$(value); }\n" + "inline void Add$RName$(const $pointer_type$* value, size_t size) { add_$name$(value, size); }\n" + "inline const ::google::protobuf::RepeatedPtrField<TProtoStringType>& Get$RName$() const" + "{ return $name$(); }\n" + "inline ::google::protobuf::RepeatedPtrField<TProtoStringType>* Mutable$RName$()" + "{ return mutable_$name$(); }\n" + ); + + if (Field_->options().ctype() != FieldOptions::STRING) { + printer->Outdent(); + printer->Print(" public:\n"); + printer->Indent(); + } + } + + void GenerateJSONPrinting(io::Printer* printer) override { + GenerateRepeatedJSONPrinting( + printer, + "::google::protobuf::io::PrintJSONString(out, Get$rname$(_index))" + ); + } + }; + + class TEnumFieldExtGenerator: public TFieldExtGenerator { + public: + TEnumFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + { + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + Variables_["type"] = ClassName(Field_->enum_type(), true); + + printer->Print(Variables_, + "inline $type$ Get$rname$() const { return $name$(); }\n" + "inline void Set$rname$($type$ value) { set_$name$(value); }\n"); + + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline $type$ Get$RName$() const { return $name$(); } \n" + "inline void Set$RName$($type$ value) { set_$name$(value); }\n" + ); + } + + void GenerateJSONPrinting(io::Printer* printer) override { + printer->Print(Variables_, "out << (int)Get$rname$();\n"); + } + }; + + class TRepeatedEnumFieldExtGenerator: public TFieldExtGenerator { + public: + TRepeatedEnumFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + { + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + Variables_["type"] = ClassName(Field_->enum_type(), true); + + printer->Print(Variables_, + "inline $type$ Get$rname$(size_t _index) const {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return $name$(_index); }\n" + "inline void Set$rname$(size_t _index, $type$ value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value); }\n" + "inline void Add$rname$($type$ value) { add_$name$(value); }\n" + "inline $type$ get_idx_$name$(int _index) const {return $name$(_index); }\n" + "inline const ::google::protobuf::RepeatedField<int>& get_arr_$name$() const { return $name$(); }\n" + "inline const ::google::protobuf::RepeatedField<int>& Get$rname$() const { return $name$(); }\n" + "inline ::google::protobuf::RepeatedField<int>* Mutable$rname$() { return mutable_$name$(); }\n"); + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline $type$ Get$RName$(size_t _index) const {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return $name$(_index); }\n" + "inline void Set$RName$(size_t _index, $type$ value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value); }\n" + "inline void Add$RName$($type$ value) { add_$name$(value); }\n" + "inline const ::google::protobuf::RepeatedField<int>& Get$RName$() const { return $name$(); }\n" + "inline ::google::protobuf::RepeatedField<int>* Mutable$RName$() { return mutable_$name$(); }\n" + ); + } + + void GenerateJSONPrinting(io::Printer* printer) override { + GenerateRepeatedJSONPrinting(printer, "out << (int)Get$rname$(_index)"); + } + }; + + class TPrimitiveFieldExtGenerator: public TFieldExtGenerator { + public: + TPrimitiveFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + { + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + Variables_["type"] = PrimitiveTypeName(Field_->cpp_type()); + + printer->Print(Variables_, + "inline $type$ Get$rname$() const { return $name$();}\n" + "inline void Set$rname$($type$ value) { set_$name$(value); }\n"); + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline $type$ Get$RName$() const { return $name$();}\n" + "inline void Set$RName$($type$ value) { set_$name$(value); }\n" + ); + } + + void GenerateJSONPrinting(io::Printer* printer) override { + printer->Print(Variables_, "out << Get$rname$();\n"); + } + }; + + class TRepeatedPrimitiveFieldExtGenerator: public TFieldExtGenerator { + public: + TRepeatedPrimitiveFieldExtGenerator(const FieldDescriptor* field) + : TFieldExtGenerator(field) + { + } + + void GenerateAccessorDeclarations(io::Printer* printer) { + Variables_["type"] = PrimitiveTypeName(Field_->cpp_type()); + + printer->Print(Variables_, + "inline $type$ Get$rname$(size_t _index) const {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return $name$(_index); }\n" + "inline void Set$rname$(size_t _index, $type$ value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value); }\n" + "inline void Add$rname$($type$ value) { add_$name$(value); }\n" + "inline $type$ get_idx_$name$(int _index) const { return $name$(_index); }\n" + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + " get_arr_$name$() const { return $name$(); }\n" + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + " Get$rname$() const { return $name$(); }\n" + "inline ::google::protobuf::RepeatedField< $type$ >*\n" + " Mutable$rname$() { return mutable_$name$(); }\n"); + if (Variables_.end() != Variables_.find("RName")) + printer->Print(Variables_, + "inline $type$ Get$RName$(size_t _index) const {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); return $name$(_index); }\n" + "inline void Set$RName$(size_t _index, $type$ value) {Y_ASSERT(_index < static_cast<size_t>(::Max<int>())); set_$name$(_index, value); }\n" + "inline void Add$RName$($type$ value) { add_$name$(value); }\n" + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + " Get$RName$() const { return $name$(); }\n" + "inline ::google::protobuf::RepeatedField< $type$ >*\n" + " Mutable$RName$() { return mutable_$name$(); }\n" + ); + } + + void GenerateJSONPrinting(io::Printer* printer) override { + GenerateRepeatedJSONPrinting(printer, "out << Get$rname$(_index)"); + } + }; + + class TBoolFieldExtGenerator: public TPrimitiveFieldExtGenerator { + public: + TBoolFieldExtGenerator(const FieldDescriptor* field) + : TPrimitiveFieldExtGenerator(field) + { + } + + void GenerateJSONPrinting(io::Printer* printer) override { + printer->Print(Variables_, "out << (Get$rname$() ? \"true\" : \"false\");\n"); + } + }; + + class TRepeatedBoolFieldExtGenerator: public TRepeatedPrimitiveFieldExtGenerator { + public: + TRepeatedBoolFieldExtGenerator(const FieldDescriptor* field) + : TRepeatedPrimitiveFieldExtGenerator(field) + { + } + + void GenerateJSONPrinting(io::Printer* printer) override { + GenerateRepeatedJSONPrinting(printer, "out << (Get$rname$(_index) ? \"true\" : \"false\")"); + } + }; + + class TFloatFieldExtGenerator: public TPrimitiveFieldExtGenerator { + public: + TFloatFieldExtGenerator(const FieldDescriptor* field) + : TPrimitiveFieldExtGenerator(field) + { + } + + void GenerateJSONPrinting(io::Printer* printer) override { + printer->Print(Variables_, "out << double(Get$rname$());\n"); + } + }; + + class TRepeatedFloatFieldExtGenerator: public TRepeatedPrimitiveFieldExtGenerator { + public: + TRepeatedFloatFieldExtGenerator(const FieldDescriptor* field) + : TRepeatedPrimitiveFieldExtGenerator(field) + { + } + + void GenerateJSONPrinting(io::Printer* printer) override { + GenerateRepeatedJSONPrinting(printer, "out << double(Get$rname$(_index))"); + } + }; + + // borrowed mostly from protobuf/compiler/cpp/cpp_extension.cc + class TExtensionGenerator { + public: + TExtensionGenerator(const FieldDescriptor* descriptor) + : Descriptor_(descriptor) + { + if (Descriptor_->is_repeated()) { + type_traits_ = "Repeated"; + } + + TProtoStringType clsName; + switch (Descriptor_->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + type_traits_.append("EnumTypeTraits< "); + clsName = ClassName(Descriptor_->enum_type(), true); + type_traits_.append(clsName); + type_traits_.append(", "); + type_traits_.append(clsName); + type_traits_.append("_IsValid>"); + break; + case FieldDescriptor::CPPTYPE_STRING: + type_traits_.append("StringTypeTraits"); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + type_traits_.append("MessageTypeTraits< "); + type_traits_.append(ClassName(Descriptor_->message_type(), true)); + type_traits_.append(" >"); + break; + default: + type_traits_.append("PrimitiveTypeTraits< "); + type_traits_.append(PrimitiveTypeName(Descriptor_->cpp_type())); + type_traits_.append(" >"); + break; + } + } + + void GenerateDeclaration(io::Printer* printer) const + { + TVariables vars; + vars["extendee" ] = ClassName(Descriptor_->containing_type(), true); + vars["type_traits" ] = type_traits_; + vars["name" ] = Descriptor_->name(); + vars["field_type" ] = SimpleItoa(static_cast<int>(Descriptor_->type())); + vars["packed" ] = Descriptor_->options().packed() ? "true" : "false"; + + printer->Print(vars, + "typedef ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" + " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" + " Td$name$;\n" + ); + } + + private: + const FieldDescriptor* Descriptor_; + TProtoStringType type_traits_; + }; + + class TOneofGenerator { + public: + TOneofGenerator(const OneofDescriptor* Descriptor_) + : Descriptor_(Descriptor_) + { + Variables_["camel_oneof_name"] = UnderscoresToCamelCase(Descriptor_->name(), true); + Variables_["rname"] = Descriptor_->name(); + } + + void GenerateDeclarations(io::Printer* printer) const { + printer->Print(Variables_, "$camel_oneof_name$Case Get$rname$Case() const { return $rname$_case(); }\n"); + printer->Print(Variables_, "void Clear$rname$() { clear_$rname$(); }\n"); + + if (Descriptor_->name() != UnderscoresToCamelCase(Descriptor_->name(), true)) { + printer->Print(Variables_, "$camel_oneof_name$Case Get$camel_oneof_name$Case() const { return $rname$_case(); }\n"); + printer->Print(Variables_, "void Clear$camel_oneof_name$() { clear_$rname$(); }\n"); + } + } + + private: + const OneofDescriptor* Descriptor_; + TVariables Variables_; + }; + + TFieldExtGenerator* MakeGenerator(const FieldDescriptor* field) { + if (field->is_repeated()) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + if (field->is_map()) { + return new TMapFieldExtGenerator(field); + } + return new TRepeatedMessageFieldExtGenerator(field); + case FieldDescriptor::CPPTYPE_BOOL: + return new TRepeatedBoolFieldExtGenerator(field); + case FieldDescriptor::CPPTYPE_FLOAT: + return new TRepeatedFloatFieldExtGenerator(field); + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // RepeatedStringFieldExtGenerator handles unknown ctypes. + case FieldOptions::STRING: + return new TRepeatedStringFieldExtGenerator(field); + } + case FieldDescriptor::CPPTYPE_ENUM: + return new TRepeatedEnumFieldExtGenerator(field); + default: + return new TRepeatedPrimitiveFieldExtGenerator(field); + } + } else { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + return new TMessageFieldExtGenerator(field); + case FieldDescriptor::CPPTYPE_BOOL: + return new TBoolFieldExtGenerator(field); + case FieldDescriptor::CPPTYPE_FLOAT: + return new TFloatFieldExtGenerator(field); + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // StringFieldGenerator handles unknown ctypes. + case FieldOptions::STRING: + return new TStringFieldExtGenerator(field); + } + case FieldDescriptor::CPPTYPE_ENUM: + return new TEnumFieldExtGenerator(field); + default: + return new TPrimitiveFieldExtGenerator(field); + } + } + } + + class TMessageExtGenerator { + public: + TMessageExtGenerator(const Descriptor* descriptor, OutputDirectory* outputDirectory) + : Descriptor_(descriptor) + , Classname_(ClassName(descriptor, false)) + , OutputDirectory_(outputDirectory) + { + for (int i = 0, idx = 0; i < descriptor->nested_type_count(); i++) { + if (!IsAutogeneratedNestedType(descriptor->nested_type(i))) { + NestedGenerators_.emplace_back(descriptor->nested_type(i), OutputDirectory_); + } + } + + FieldGenerators_.reserve(descriptor->field_count()); + for (int i = 0; i < descriptor->field_count(); i++) { + FieldGenerators_.emplace_back(MakeGenerator(descriptor->field(i))); + } + + ExtensionGenerators_.reserve(descriptor->extension_count()); + for (int i = 0; i < descriptor->extension_count(); i++) { + ExtensionGenerators_.emplace_back(descriptor->extension(i)); + } + + OneofGenerators_.reserve(descriptor->real_oneof_decl_count()); + for (int i = 0; i < descriptor->real_oneof_decl_count(); i++) { + OneofGenerators_.emplace_back(descriptor->oneof_decl(i)); + } + } + + void GenerateClassDefinitionExtension() { + GenerateSaveLoadImplementation(); + GenerateJSONImplementation(); + + for (auto& nestedGenerator: NestedGenerators_) { + nestedGenerator.GenerateClassDefinitionExtension(); + } + } + + void GenerateDebugOutputExtension() { + GenerateDebugOutput(); + + for (auto& nestedGenerator: NestedGenerators_) { + nestedGenerator.GenerateDebugOutputExtension(); + } + } + + void GenerateTypedefOutputExtension(bool nested) { + GenerateTypedefOutput(nested); + + for (auto& nestedGenerator: NestedGenerators_) { + nestedGenerator.GenerateTypedefOutputExtension(true); + } + } + + + void GenerateClassExtension() { + GenerateDebugStringImplementation(); + for (auto& nestedGenerator: NestedGenerators_) { + nestedGenerator.GenerateClassExtension(); + } + } + + void GenerateDeclarations() { + GenerateFieldAccessorDeclarations(); + + for (auto& nestedGenerator: NestedGenerators_) { + nestedGenerator.GenerateDeclarations(); + } + } + + void GenerateDefinitions() { + GenerateClassExtension(); + GenerateDebugOutputExtension(); + GenerateClassDefinitionExtension(); + } + + private: + void GenerateFieldAccessorDeclarations() { + TProtoStringType fileName = HeaderFileName(Descriptor_->file()); + TProtoStringType scope = "class_scope:" + Descriptor_->full_name(); + std::unique_ptr<io::ZeroCopyOutputStream> output( + OutputDirectory_->OpenForInsert(fileName, scope)); + io::Printer printer(output.get(), '$'); + + printer.Print("// Yandex cpp-styleguide extension\n"); + for (int i = 0; i < Descriptor_->field_count(); i++) { + const FieldDescriptor* field = Descriptor_->field(i); + + TVariables vars; + SetCommonFieldVariables(field, &vars); + + const bool hasRName = (vars.end() != vars.find("RName")); + if (field->is_repeated()) { + printer.Print(vars, + "inline size_t $rname$Size() const { return (size_t)$name$_size(); }\n"); + if (hasRName) + printer.Print(vars, + "inline size_t $RName$Size() const { return (size_t)$name$_size(); }\n"); + } else if (field->has_presence()) { + printer.Print(vars, + "inline bool Has$rname$() const { return has_$name$(); }\n"); + if (hasRName) + printer.Print(vars, + "inline bool Has$RName$() const { return has_$name$(); }\n"); + } + + printer.Print(vars, "inline void Clear$rname$() { clear_$name$(); }\n"); + if (hasRName) + printer.Print(vars, + "inline void Clear$RName$() { clear_$name$(); }\n"); + + // Generate type-specific accessor declarations. + FieldGenerators_[i]->GenerateAccessorDeclarations(&printer); + + printer.Print("\n"); + } + for (auto& extensionGenerator: ExtensionGenerators_) { + extensionGenerator.GenerateDeclaration(&printer); + } + for (auto& oneofGenerator: OneofGenerators_) { + oneofGenerator.GenerateDeclarations(&printer); + } + TVariables vars; + vars["class"] = ClassName(Descriptor_, false); + if (!IsLiteRuntimeMessage(Descriptor_)) { + printer.Print("TProtoStringType ShortUtf8DebugString() const;\n"); + + printer.Print("void PrintJSON(IOutputStream&) const override;\n"); + printer.Print(vars, "::google::protobuf::io::TAsJSON<$class$> AsJSON() const {\n"); + printer.Print(vars, " return ::google::protobuf::io::TAsJSON<$class$>(*this);\n"); + printer.Print("}\n"); + + printer.Print("void Save(IOutputStream* output) const;\n"); + printer.Print("void Load(IInputStream* input);\n"); + } + printer.Print("// End of Yandex-specific extension\n"); + } + + void GenerateSaveLoadImplementation() { + TProtoStringType fileName = SourceFileName(Descriptor_->file()); + TProtoStringType scope = "namespace_scope"; + std::unique_ptr<io::ZeroCopyOutputStream> output( + OutputDirectory_->OpenForInsert(fileName, scope)); + io::Printer printer(output.get(), '$'); + + TVariables vars; + vars["class"] = Classname_; + if (!IsLiteRuntimeMessage(Descriptor_)) { + printer.Print("// Yandex-specific extension\n"); + printer.Print(vars, "void $class$::Save(IOutputStream* output) const {\n"); + printer.Print(" ::Save(output, static_cast<const ::google::protobuf::Message&>(*this));\n"); + printer.Print("}\n"); + printer.Print(vars, "void $class$::Load(IInputStream* input) {\n"); + printer.Print(" ::Load(input, static_cast<::google::protobuf::Message&>(*this));\n"); + printer.Print("}\n"); + printer.Print("// End of Yandex-specific extension\n"); + } + } + + void GenerateDebugStringImplementation() { + TProtoStringType fileName = SourceFileName(Descriptor_->file()); + TProtoStringType scope = "namespace_scope"; + std::unique_ptr<io::ZeroCopyOutputStream> output( + OutputDirectory_->OpenForInsert(fileName, scope)); + io::Printer printer(output.get(), '$'); + + TVariables vars; + vars["class"] = Classname_; + if (!IsLiteRuntimeMessage(Descriptor_)) { + printer.Print("// Yandex-specific extension\n"); + printer.Print(vars, "TProtoStringType $class$::ShortUtf8DebugString() const {\n"); + printer.Print(" return ::ShortUtf8DebugString(*this);\n"); + printer.Print("}\n"); + printer.Print("// End of Yandex-specific extension\n"); + } + } + + void GenerateJSONImplementation() { + if (IsLiteRuntimeMessage(Descriptor_)) { + return; + } + + TProtoStringType fileName = SourceFileName(Descriptor_->file()); + TProtoStringType scope = "namespace_scope"; + std::unique_ptr<io::ZeroCopyOutputStream> output( + OutputDirectory_->OpenForInsert(fileName, scope)); + io::Printer printer(output.get(), '$'); + printer.Print("// Yandex JSON extension\n"); + TVariables vars; + vars["class"] = ClassName(Descriptor_, true); + printer.Print(vars, "inline void $class$::PrintJSON(IOutputStream& out) const {\n"); + + printer.Indent(); + printer.Print("out << '{';\n"); + if (Descriptor_->field_count() > 0) { + printer.Print("const char* sep = \"\";\n"); + } + for (int i = 0; i < Descriptor_->field_count(); i++) { + const FieldDescriptor* field = Descriptor_->field(i); + + TVariables vars; + SetCommonFieldVariables(field, &vars); + + if (field->is_repeated()) { + // map or repeated field in both proto3 and proto2 syntax + printer.Print(vars, "if ($rname$Size() > 0) {\n"); + } else if (field->has_presence()) { + // any optional or required field in proto2 syntax + // message-field or any oneof field in proto3 syntax + printer.Print(vars, "if (Has$rname$()) {\n"); + } else { + // string, enum or primitive field in proto3 syntax + printer.Print(vars, "if (Get$rname$()) {\n"); + } + + printer.Indent(); + printer.Print("out << sep;\n"); + printer.Print(vars, "out << \"\\\"$rname$\\\":\";\n"); + FieldGenerators_[i]->GenerateJSONPrinting(&printer); + printer.Print(vars, "sep = \",\";\n"); + printer.Outdent(); + printer.Print("}\n"); + } + printer.Print("out << '}';\n"); + printer.Outdent(); + printer.Print("}\n"); + + printer.Print("// End of Yandex JSON extension\n"); + } + + void GenerateDebugOutput() { + TProtoStringType fileName = SourceFileName(Descriptor_->file()); + TProtoStringType scope = "global_scope"; + std::unique_ptr<io::ZeroCopyOutputStream> output( + OutputDirectory_->OpenForInsert(fileName, scope)); + io::Printer printer(output.get(), '$'); + if (!IsLiteRuntimeMessage(Descriptor_)) { + printer.Print("// Yandex debug output extension\n"); + TVariables vars; + vars["class"] = ClassName(Descriptor_, true); + printer.Print("template<>\n"); + printer.Print(vars, "void Out< $class$>(IOutputStream& out, const $class$& msg) {\n"); + printer.Print(" out << \"{ \" << msg.ShortUtf8DebugString() << \" }\";\n"); + printer.Print("}\n"); + printer.Print("// End of Yandex debug output extension\n"); + } + } + + void GenerateTypedefOutput(bool nested) { + if (!GenerateYaStyle(Descriptor_->file())) + return; + TProtoStringType fileName = HeaderFileName(Descriptor_->file()); + TProtoStringType scope = nested ? "class_scope:" + Descriptor_->full_name().substr(0, + Descriptor_->full_name().size() - Descriptor_->name().size() - 1) + : "namespace_scope"; + std::unique_ptr<io::ZeroCopyOutputStream> output( + OutputDirectory_->OpenForInsert(fileName, scope)); + io::Printer printer(output.get(), '$'); + TString name = Descriptor_->name(); + bool isOk = name.size() >= 2 && name[0] == 'T' && name[1] >= 'A' && name[1] <= 'Z'; + if (!isOk) { + printer.Print("// Yandex typedef extension\n"); + TVariables vars; + vars["class"] = name; + vars["base_class"] = ClassName(Descriptor_, true); + printer.Print(vars, "typedef $base_class$ T$class$;\n"); + printer.Print("// End of Yandex typedef extension\n"); + } + } + + + private: + const Descriptor* Descriptor_; + TProtoStringType Classname_; + OutputDirectory* OutputDirectory_; + std::vector<std::unique_ptr<TFieldExtGenerator>> FieldGenerators_; + std::vector<TMessageExtGenerator> NestedGenerators_; + std::vector<TExtensionGenerator> ExtensionGenerators_; + std::vector<TOneofGenerator> OneofGenerators_; + }; + + class TFileExtGenerator { + public: + TFileExtGenerator(const FileDescriptor* file, OutputDirectory* output_directory) + : File_(file) + , OutputDirectory_(output_directory) + { + MessageGenerators_.reserve(file->message_type_count()); + for (size_t i = 0; i < file->message_type_count(); i++) { + MessageGenerators_.emplace_back(file->message_type(i), OutputDirectory_); + } + } + + void GenerateHeaderExtensions() { + GenerateHeaderIncludeExtensions(); + + for (auto& messageGenerator: MessageGenerators_) { + messageGenerator.GenerateTypedefOutputExtension(false); + messageGenerator.GenerateDeclarations(); + } + } + + void GenerateSourceExtensions() { + GenerateSourceIncludeExtensions(); + + for (auto& messageGenerator: MessageGenerators_) { + messageGenerator.GenerateDefinitions(); + } + } + + private: + void GenerateSourceIncludeExtensions() { + TProtoStringType fileName = SourceFileName(File_); + TProtoStringType scope = "includes"; + std::unique_ptr<io::ZeroCopyOutputStream> output( + OutputDirectory_->OpenForInsert(fileName, scope)); + io::Printer printer(output.get(), '$'); + printer.Print("#include <google/protobuf/messagext.h>\n"); + } + + void GenerateHeaderIncludeExtensions() { + TProtoStringType fileName = HeaderFileName(File_); + TProtoStringType scope = "includes"; + std::unique_ptr<io::ZeroCopyOutputStream> output( + OutputDirectory_->OpenForInsert(fileName, scope)); + io::Printer printer(output.get(), '$'); + printer.Print("#include <google/protobuf/json_util.h>\n"); + } + + private: + const FileDescriptor* File_; + OutputDirectory* OutputDirectory_; + size_t MessageTypeCount_; + std::vector<TMessageExtGenerator> MessageGenerators_; + }; + + bool TCppStyleGuideExtensionGenerator::Generate(const FileDescriptor* file, + const TProtoStringType&, + OutputDirectory* outputDirectory, + TProtoStringType*) const { + + TFileExtGenerator fileGenerator(file, outputDirectory); + + // Generate header. + fileGenerator.GenerateHeaderExtensions(); + + // Generate cc file. + fileGenerator.GenerateSourceExtensions(); + + return true; + } + +} +} +} + +int main(int argc, char* argv[]) { +#ifdef _MSC_VER + // Don't print a silly message or stick a modal dialog box in my face, + // please. + _set_abort_behavior(0, ~0); +#endif // !_MSC_VER + + NProtobuf::NCompiler::NPlugins::TCppStyleGuideExtensionGenerator generator; + return google::protobuf::compiler::PluginMain(argc, argv, &generator); +} |