diff options
author | nechda <nechda@yandex-team.com> | 2024-08-29 23:50:27 +0300 |
---|---|---|
committer | nechda <nechda@yandex-team.com> | 2024-08-30 00:05:25 +0300 |
commit | e10d6638f07a82edae3ea8197b9f5c0affcc07ea (patch) | |
tree | 571c38cec05813766a1ad290c9d51ce7ace52919 /contrib/libs/protoc/src/google/protobuf/compiler/objectivec | |
parent | e79b38f2bbbf78d295d1901d2a79f898022d5224 (diff) | |
download | ydb-e10d6638f07a82edae3ea8197b9f5c0affcc07ea.tar.gz |
Update cpp-protobuf to 22.5
Привет!\
Этот PR переключат cpp & python библиотеки protobuf на версию 22.5
Если у вас возникли проблемы после влития этого PR:
1. Если начали падать канон тесты, то проведите их переканонизацию
2. Прочитайте <https://wiki.yandex-team.ru/users/nechda/obnovlenie-cpp-protobuf-22.5/> страничку с основными изменениями
3. Если страничка в вики не помогла, то пишите в [DEVTOOLSSUPPORT](https://st.yandex-team.ru/DEVTOOLSSUPPORT)
7fecade616c20a841b9e9af7b7998bdfc8d2807d
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/objectivec')
39 files changed, 5385 insertions, 4448 deletions
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/enum.cc index 39c7829576..5b23792af4 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_enum.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/enum.cc @@ -28,23 +28,38 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <map> +#include "google/protobuf/compiler/objectivec/enum.h" + +#include <algorithm> +#include <limits> #include <string> -#include <google/protobuf/compiler/objectivec/objectivec_enum.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> -#include <algorithm> // std::find() +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/strings/escaping.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace objectivec { +namespace { +TProtoStringType SafelyPrintIntToCode(int v) { + if (v == std::numeric_limits<int>::min()) { + // Some compilers try to parse -2147483648 as two tokens and then get spicy + // about the fact that +2147483648 cannot be represented as an int. + return y_absl::StrCat(v + 1, " - 1"); + } else { + return y_absl::StrCat(v); + } +} +} // namespace EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) - : descriptor_(descriptor), - name_(EnumName(descriptor_)) { + : descriptor_(descriptor), name_(EnumName(descriptor_)) { // Track the names for the enum values, and if an alias overlaps a base // value, skip making a name for it. Likewise if two alias overlap, the // first one wins. @@ -54,7 +69,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) // compile error is just fine. // The values are still tracked to support the reflection apis and // TextFormat handing since they are different there. - std::set<TProtoStringType> value_names; + y_absl::flat_hash_set<TProtoStringType> value_names; for (int i = 0; i < descriptor_->value_count(); i++) { const EnumValueDescriptor* value = descriptor_->value(i); @@ -65,20 +80,15 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) base_values_.push_back(value); value_names.insert(EnumValueName(value)); } else { - TProtoStringType value_name(EnumValueName(value)); - if (value_names.find(value_name) != value_names.end()) { + if (!value_names.insert(EnumValueName(value)).second) { alias_values_to_skip_.insert(value); - } else { - value_names.insert(value_name); } } all_values_.push_back(value); } } -EnumGenerator::~EnumGenerator() {} - -void EnumGenerator::GenerateHeader(io::Printer* printer) { +void EnumGenerator::GenerateHeader(io::Printer* printer) const { TProtoStringType enum_comments; SourceLocation location; if (descriptor_->GetSourceLocation(&location)) { @@ -106,45 +116,49 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { // doesn't have to bother with the `enum_extensibility` attribute, as the // default will be what is needed. - printer->Print("$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n", - "comments", enum_comments, - "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()), - "name", name_); + printer->Print( + "$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n", + "comments", enum_comments, "deprecated_attribute", + GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()), "name", + name_); printer->Indent(); - if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { + if (!descriptor_->is_closed()) { // Include the unknown value. printer->Print( - "/**\n" - " * Value used if any message's field encounters a value that is not defined\n" - " * by this enum. The message will also have C functions to get/set the rawValue\n" - " * of the field.\n" - " **/\n" - "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n", - "name", name_); + // clang-format off + "/**\n" + " * Value used if any message's field encounters a value that is not defined\n" + " * by this enum. The message will also have C functions to get/set the rawValue\n" + " * of the field.\n" + " **/\n" + "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n", + // clang-format on + "name", name_); } for (int i = 0; i < all_values_.size(); i++) { - if (alias_values_to_skip_.find(all_values_[i]) != alias_values_to_skip_.end()) { + if (alias_values_to_skip_.find(all_values_[i]) != + alias_values_to_skip_.end()) { continue; } if (all_values_[i]->GetSourceLocation(&location)) { - TProtoStringType comments = BuildCommentsString(location, true).c_str(); + TProtoStringType comments = BuildCommentsString(location, true); if (comments.length() > 0) { if (i > 0) { printer->Print("\n"); } - printer->Print(comments.c_str()); + printer->Print(comments); } } - printer->Print( - "$name$$deprecated_attribute$ = $value$,\n", - "name", EnumValueName(all_values_[i]), - "deprecated_attribute", GetOptionalDeprecatedAttribute(all_values_[i]), - "value", StrCat(all_values_[i]->number())); + printer->Print("$name$$deprecated_attribute$ = $value$,\n", "name", + EnumValueName(all_values_[i]), "deprecated_attribute", + GetOptionalDeprecatedAttribute(all_values_[i]), "value", + SafelyPrintIntToCode(all_values_[i]->number())); } printer->Outdent(); printer->Print( + // clang-format off "};\n" "\n" "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n" @@ -154,11 +168,12 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { " * the time this source was generated.\n" " **/\n" "BOOL $name$_IsValidValue(arc_i32 value);\n" + // clang-format on "\n", "name", name_); } -void EnumGenerator::GenerateSource(io::Printer* printer) { +void EnumGenerator::GenerateSource(io::Printer* printer) const { printer->Print( "#pragma mark - Enum $name$\n" "\n", @@ -184,38 +199,47 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { } printer->Print( + // clang-format off "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n" " static _Atomic(GPBEnumDescriptor*) descriptor = nil;\n" - " if (!descriptor) {\n", + " if (!descriptor) {\n" + " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n", + // clang-format on "name", name_); static const int kBytesPerLine = 40; // allow for escaping - printer->Print( - " static const char *valueNames ="); + printer->Print(" static const char *valueNames ="); for (int i = 0; i < text_blob.size(); i += kBytesPerLine) { printer->Print( - "\n \"$data$\"", - "data", EscapeTrigraphs(CEscape(text_blob.substr(i, kBytesPerLine)))); + "\n \"$data$\"", "data", + EscapeTrigraphs(y_absl::CEscape(text_blob.substr(i, kBytesPerLine)))); } printer->Print( ";\n" " static const arc_i32 values[] = {\n"); for (int i = 0; i < all_values_.size(); i++) { - printer->Print(" $name$,\n", "name", EnumValueName(all_values_[i])); + printer->Print(" $name$,\n", "name", EnumValueName(all_values_[i])); } printer->Print(" };\n"); if (text_format_decode_data.num_entries() == 0) { printer->Print( + // clang-format off " GPBEnumDescriptor *worker =\n" " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" " valueNames:valueNames\n" " values:values\n" " count:(arc_ui32)(sizeof(values) / sizeof(arc_i32))\n" - " enumVerifier:$name$_IsValidValue];\n", - "name", name_); - } else { - printer->Print( + " enumVerifier:$name$_IsValidValue\n" + " flags:$flags$];\n", + // clang-format on + "name", name_, "flags", + (descriptor_->is_closed() + ? "GPBEnumDescriptorInitializationFlag_IsClosed" + : "GPBEnumDescriptorInitializationFlag_None")); + } else { + printer->Print( + // clang-format off " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" " GPBEnumDescriptor *worker =\n" " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" @@ -223,36 +247,46 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { " values:values\n" " count:(arc_ui32)(sizeof(values) / sizeof(arc_i32))\n" " enumVerifier:$name$_IsValidValue\n" + " flags:$flags$\n" " extraTextFormatInfo:extraTextFormatInfo];\n", - "name", name_, - "extraTextFormatInfo", CEscape(text_format_decode_data.Data())); - } - printer->Print( - " GPBEnumDescriptor *expected = nil;\n" - " if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) {\n" - " [worker release];\n" - " }\n" - " }\n" - " return descriptor;\n" - "}\n\n"); + // clang-format on + "name", name_, "flags", + (descriptor_->is_closed() + ? "GPBEnumDescriptorInitializationFlag_IsClosed" + : "GPBEnumDescriptorInitializationFlag_None"), + "extraTextFormatInfo", y_absl::CEscape(text_format_decode_data.Data())); + } + // clang-format off + printer->Print( + " GPBEnumDescriptor *expected = nil;\n" + " if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) {\n" + " [worker release];\n" + " }\n" + " }\n" + " return descriptor;\n" + "}\n\n"); + // clang-format on printer->Print( + // clang-format off "BOOL $name$_IsValidValue(arc_i32 value__) {\n" " switch (value__) {\n", + // clang-format on "name", name_); for (int i = 0; i < base_values_.size(); i++) { - printer->Print( - " case $name$:\n", - "name", EnumValueName(base_values_[i])); + printer->Print(" case $name$:\n", "name", + EnumValueName(base_values_[i])); } + // clang-format off printer->Print( " return YES;\n" " default:\n" " return NO;\n" " }\n" "}\n\n"); + // clang-format on } } // namespace objectivec } // namespace compiler diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_enum.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/enum.h index 4d0404bcb3..962620feba 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_enum.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/enum.h @@ -32,10 +32,11 @@ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ #include <string> -#include <set> #include <vector> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/io/printer.h> + +#include "y_absl/container/flat_hash_set.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -45,13 +46,13 @@ namespace objectivec { class EnumGenerator { public: explicit EnumGenerator(const EnumDescriptor* descriptor); - ~EnumGenerator(); + ~EnumGenerator() = default; EnumGenerator(const EnumGenerator&) = delete; EnumGenerator& operator=(const EnumGenerator&) = delete; - void GenerateHeader(io::Printer* printer); - void GenerateSource(io::Printer* printer); + void GenerateHeader(io::Printer* printer) const; + void GenerateSource(io::Printer* printer) const; const TProtoStringType& name() const { return name_; } @@ -59,7 +60,7 @@ class EnumGenerator { const EnumDescriptor* descriptor_; std::vector<const EnumValueDescriptor*> base_values_; std::vector<const EnumValueDescriptor*> all_values_; - std::set<const EnumValueDescriptor*> alias_values_to_skip_; + y_absl::flat_hash_set<const EnumValueDescriptor*> alias_values_to_skip_; const TProtoStringType name_; }; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/enum_field.cc index bcecc7b373..c470c24158 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/enum_field.cc @@ -28,12 +28,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <map> +#include "google/protobuf/compiler/objectivec/enum_field.h" + #include <string> -#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/io/printer.h> +#include "y_absl/container/flat_hash_map.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -42,22 +44,24 @@ namespace objectivec { namespace { -void SetEnumVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables) { - TProtoStringType type = EnumName(descriptor->enum_type()); +void SetEnumVariables( + const FieldDescriptor* descriptor, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables) { + const TProtoStringType type = EnumName(descriptor->enum_type()); + const TProtoStringType enum_desc_func = y_absl::StrCat(type, "_EnumDescriptor"); (*variables)["storage_type"] = type; // For non repeated fields, if it was defined in a different file, the // property decls need to use "enum NAME" rather than just "NAME" to support // the forward declaration of the enums. if (!descriptor->is_repeated() && (descriptor->file() != descriptor->enum_type()->file())) { - (*variables)["property_type"] = "enum " + type; + (*variables)["property_type"] = y_absl::StrCat("enum ", type); } - (*variables)["enum_verifier"] = type + "_IsValidValue"; - (*variables)["enum_desc_func"] = type + "_EnumDescriptor"; + (*variables)["enum_verifier"] = y_absl::StrCat(type, "_IsValidValue"); + (*variables)["enum_desc_func"] = enum_desc_func; (*variables)["dataTypeSpecific_name"] = "enumDescFunc"; - (*variables)["dataTypeSpecific_value"] = (*variables)["enum_desc_func"]; + (*variables)["dataTypeSpecific_value"] = enum_desc_func; const Descriptor* msg_descriptor = descriptor->containing_type(); (*variables)["owning_message_class"] = ClassName(msg_descriptor); @@ -69,14 +73,13 @@ EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor) SetEnumVariables(descriptor, &variables_); } -EnumFieldGenerator::~EnumFieldGenerator() {} - void EnumFieldGenerator::GenerateCFunctionDeclarations( io::Printer* printer) const { - if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { + if (descriptor_->enum_type()->is_closed()) { return; } + // clang-format off printer->Print( variables_, "/**\n" @@ -91,12 +94,16 @@ void EnumFieldGenerator::GenerateCFunctionDeclarations( " **/\n" "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, arc_i32 value);\n" "\n"); + // clang-format on } void EnumFieldGenerator::GenerateCFunctionImplementations( io::Printer* printer) const { - if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) return; + if (descriptor_->enum_type()->is_closed()) { + return; + } + // clang-format off printer->Print( variables_, "arc_i32 $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message) {\n" @@ -111,13 +118,14 @@ void EnumFieldGenerator::GenerateCFunctionImplementations( " GPBSetMessageRawEnumField(message, field, value);\n" "}\n" "\n"); + // clang-format on } void EnumFieldGenerator::DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, + y_absl::btree_set<TProtoStringType>* fwd_decls, bool include_external_types) const { - SingleFieldGenerator::DetermineForwardDeclarations( - fwd_decls, include_external_types); + SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls, + include_external_types); // If it is an enum defined in a different file (and not a WKT), then we'll // need a forward declaration for it. When it is in our file, all the enums // are output before the message, so it will be declared before it is needed. @@ -126,7 +134,7 @@ void EnumFieldGenerator::DetermineForwardDeclarations( !IsProtobufLibraryBundledProtoFile(descriptor_->enum_type()->file())) { // Enum name is already in "storage_type". const TProtoStringType& name = variable("storage_type"); - fwd_decls->insert("GPB_ENUM_FWD_DECLARE(" + name + ")"); + fwd_decls->insert(y_absl::StrCat("GPB_ENUM_FWD_DECLARE(", name, ");")); } } @@ -137,14 +145,18 @@ RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( variables_["array_storage_type"] = "GPBEnumArray"; } -RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} - -void RepeatedEnumFieldGenerator::FinishInitialization(void) { +void RepeatedEnumFieldGenerator::FinishInitialization() { RepeatedFieldGenerator::FinishInitialization(); + TProtoStringType name = variables_["name"]; + TProtoStringType storage_type = variables_["storage_type"]; variables_["array_comment"] = - "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; + y_absl::StrCat("// |", name, "| contains |", storage_type, "|\n"); } +// NOTE: RepeatedEnumFieldGenerator::DetermineForwardDeclarations isn't needed +// because `GPBEnumArray` isn't generic (like `NSArray` would be for messages) +// and thus doesn't reference the type in the header. + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/enum_field.h index fea75f7a84..3220df1046 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/enum_field.h @@ -31,9 +31,10 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__ -#include <map> #include <string> -#include <google/protobuf/compiler/objectivec/objectivec_field.h> + +#include "y_absl/container/btree_set.h" +#include "google/protobuf/compiler/objectivec/field.h" namespace google { namespace protobuf { @@ -47,28 +48,25 @@ class EnumFieldGenerator : public SingleFieldGenerator { EnumFieldGenerator& operator=(const EnumFieldGenerator&) = delete; public: - virtual void GenerateCFunctionDeclarations( - io::Printer* printer) const override; - virtual void GenerateCFunctionImplementations( - io::Printer* printer) const override; - virtual void DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, - bool include_external_types) const override; + void GenerateCFunctionDeclarations(io::Printer* printer) const override; + void GenerateCFunctionImplementations(io::Printer* printer) const override; + void DetermineForwardDeclarations(y_absl::btree_set<TProtoStringType>* fwd_decls, + bool include_external_types) const override; protected: explicit EnumFieldGenerator(const FieldDescriptor* descriptor); - virtual ~EnumFieldGenerator(); + ~EnumFieldGenerator() override = default; }; class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator { friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); public: - virtual void FinishInitialization() override; + void FinishInitialization() override; protected: explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor); - virtual ~RepeatedEnumFieldGenerator(); + ~RepeatedEnumFieldGenerator() override = default; }; } // namespace objectivec diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/extension.cc index dbbce48952..4da745c9f6 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_extension.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/extension.cc @@ -28,38 +28,39 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "google/protobuf/compiler/objectivec/extension.h" + #include <iostream> +#include <ostream> +#include <string> +#include <vector> -#include <google/protobuf/compiler/objectivec/objectivec_extension.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/io/printer.h> +#include "y_absl/container/btree_set.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace objectivec { -ExtensionGenerator::ExtensionGenerator(const TProtoStringType& root_class_name, +ExtensionGenerator::ExtensionGenerator(y_absl::string_view root_class_name, const FieldDescriptor* descriptor) : method_name_(ExtensionMethodName(descriptor)), - root_class_and_method_name_(root_class_name + "_" + method_name_), + root_class_and_method_name_( + y_absl::StrCat(root_class_name, "_", method_name_)), descriptor_(descriptor) { - if (descriptor->is_map()) { - // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some - // error cases, so it seems to be ok to use as a back door for errors. - std::cerr << "error: Extension is a map<>!" - << " That used to be blocked by the compiler." << std::endl; - std::cerr.flush(); - abort(); - } + Y_ABSL_CHECK(!descriptor->is_map()) + << "error: Extension is a map<>!" + << " That used to be blocked by the compiler."; } -ExtensionGenerator::~ExtensionGenerator() {} - -void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) { - std::map<TProtoStringType, TProtoStringType> vars; +void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) const { + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars; vars["method_name"] = method_name_; if (IsRetainedName(method_name_)) { vars["storage_attribute"] = " NS_RETURNS_NOT_RETAINED"; @@ -74,19 +75,23 @@ void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) { } // Unlike normal message fields, check if the file for the extension was // deprecated. - vars["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()); - printer->Print(vars, - "$comments$" - "+ (GPBExtensionDescriptor *)$method_name$$storage_attribute$$deprecated_attribute$;\n"); + vars["deprecated_attribute"] = + GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()); + // clang-format off + printer->Print( + vars, + "$comments$" + "+ (GPBExtensionDescriptor *)$method_name$$storage_attribute$$deprecated_attribute$;\n"); + // clang-format on } void ExtensionGenerator::GenerateStaticVariablesInitialization( - io::Printer* printer) { - std::map<TProtoStringType, TProtoStringType> vars; + io::Printer* printer) const { + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars; vars["root_class_and_method_name"] = root_class_and_method_name_; const TProtoStringType containing_type = ClassName(descriptor_->containing_type()); vars["extended_type"] = ObjCClass(containing_type); - vars["number"] = StrCat(descriptor_->number()); + vars["number"] = y_absl::StrCat(descriptor_->number()); std::vector<TProtoStringType> options; if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated"); @@ -111,30 +116,33 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization( vars["default"] = DefaultValue(descriptor_); } TProtoStringType type = GetCapitalizedType(descriptor_); - vars["extension_type"] = TProtoStringType("GPBDataType") + type; + vars["extension_type"] = y_absl::StrCat("GPBDataType", type); if (objc_type == OBJECTIVECTYPE_ENUM) { vars["enum_desc_func_name"] = - EnumName(descriptor_->enum_type()) + "_EnumDescriptor"; + y_absl::StrCat(EnumName(descriptor_->enum_type()), "_EnumDescriptor"); } else { vars["enum_desc_func_name"] = "NULL"; } - printer->Print(vars, - "{\n" - " .defaultValue.$default_name$ = $default$,\n" - " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" - " .extendedClass.clazz = $extended_type$,\n" - " .messageOrGroupClass.clazz = $type$,\n" - " .enumDescriptorFunc = $enum_desc_func_name$,\n" - " .fieldNumber = $number$,\n" - " .dataType = $extension_type$,\n" - " .options = $options$,\n" - "},\n"); + // clang-format off + printer->Print( + vars, + "{\n" + " .defaultValue.$default_name$ = $default$,\n" + " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" + " .extendedClass.clazz = $extended_type$,\n" + " .messageOrGroupClass.clazz = $type$,\n" + " .enumDescriptorFunc = $enum_desc_func_name$,\n" + " .fieldNumber = $number$,\n" + " .dataType = $extension_type$,\n" + " .options = $options$,\n" + "},\n"); + // clang-format on } void ExtensionGenerator::DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) { + y_absl::btree_set<TProtoStringType>* fwd_decls) const { TProtoStringType extended_type = ClassName(descriptor_->containing_type()); fwd_decls->insert(ObjCClassDeclaration(extended_type)); ObjectiveCType objc_type = GetObjectiveCType(descriptor_); @@ -144,10 +152,13 @@ void ExtensionGenerator::DetermineObjectiveCClassDefinitions( } } -void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) { +void ExtensionGenerator::GenerateRegistrationSource( + io::Printer* printer) const { + // clang-format off printer->Print( "[registry addExtension:$root_class_and_method_name$];\n", "root_class_and_method_name", root_class_and_method_name_); + // clang-format on } } // namespace objectivec diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_extension.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/extension.h index 04e59f9284..1f81d82e74 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_extension.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/extension.h @@ -31,8 +31,11 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__ -#include <google/protobuf/descriptor.h> -#include <google/protobuf/io/printer.h> +#include <string> + +#include "y_absl/container/btree_set.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -41,17 +44,18 @@ namespace objectivec { class ExtensionGenerator { public: - ExtensionGenerator(const TProtoStringType& root_class_name, + ExtensionGenerator(y_absl::string_view root_class_name, const FieldDescriptor* descriptor); - ~ExtensionGenerator(); + ~ExtensionGenerator() = default; ExtensionGenerator(const ExtensionGenerator&) = delete; ExtensionGenerator& operator=(const ExtensionGenerator&) = delete; - void GenerateMembersHeader(io::Printer* printer); - void GenerateStaticVariablesInitialization(io::Printer* printer); - void GenerateRegistrationSource(io::Printer* printer); - void DetermineObjectiveCClassDefinitions(std::set<TProtoStringType>* fwd_decls); + void GenerateMembersHeader(io::Printer* printer) const; + void GenerateStaticVariablesInitialization(io::Printer* printer) const; + void GenerateRegistrationSource(io::Printer* printer) const; + void DetermineObjectiveCClassDefinitions( + y_absl::btree_set<TProtoStringType>* fwd_decls) const; private: TProtoStringType method_name_; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/field.cc index e73a664db1..e72185e794 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/field.cc @@ -28,16 +28,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <iostream> +#include "google/protobuf/compiler/objectivec/field.h" -#include <google/protobuf/compiler/objectivec/objectivec_field.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h> -#include <google/protobuf/compiler/objectivec/objectivec_map_field.h> -#include <google/protobuf/compiler/objectivec/objectivec_message_field.h> -#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> +#include <iostream> +#include <ostream> +#include <string> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/log/absl_log.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/objectivec/enum_field.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/map_field.h" +#include "google/protobuf/compiler/objectivec/message_field.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/primitive_field.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -46,8 +54,9 @@ namespace objectivec { namespace { -void SetCommonFieldVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables) { +void SetCommonFieldVariables( + const FieldDescriptor* descriptor, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables) { TProtoStringType camel_case_name = FieldName(descriptor); TProtoStringType raw_field_name; if (descriptor->type() == FieldDescriptor::TYPE_GROUP) { @@ -73,10 +82,11 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["capitalized_name"] = capitalized_name; (*variables)["raw_field_name"] = raw_field_name; (*variables)["field_number_name"] = - classname + "_FieldNumber_" + capitalized_name; - (*variables)["field_number"] = StrCat(descriptor->number()); + y_absl::StrCat(classname, "_FieldNumber_", capitalized_name); + (*variables)["field_number"] = y_absl::StrCat(descriptor->number()); (*variables)["field_type"] = GetCapitalizedType(descriptor); - (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor); + (*variables)["deprecated_attribute"] = + GetOptionalDeprecatedAttribute(descriptor); std::vector<TProtoStringType> field_flags; if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated"); if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired"); @@ -89,6 +99,9 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, if (needs_custom_name) field_flags.push_back("GPBFieldTextFormatNameCustom"); if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { field_flags.push_back("GPBFieldHasEnumDescriptor"); + if (descriptor->enum_type()->is_closed()) { + field_flags.push_back("GPBFieldClosedEnum"); + } } // It will clear on a zero value if... // - not repeated/map @@ -107,18 +120,63 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["dataTypeSpecific_name"] = "clazz"; (*variables)["dataTypeSpecific_value"] = "Nil"; - (*variables)["storage_offset_value"] = - "(arc_ui32)offsetof(" + classname + "__storage_, " + camel_case_name + ")"; + (*variables)["storage_offset_value"] = y_absl::StrCat( + "(arc_ui32)offsetof(", classname, "__storage_, ", camel_case_name, ")"); (*variables)["storage_offset_comment"] = ""; // Clear some common things so they can be set just when needed. (*variables)["storage_attribute"] = ""; } +bool HasNonZeroDefaultValue(const FieldDescriptor* field) { + // Repeated fields don't have defaults. + if (field->is_repeated()) { + return false; + } + + // As much as checking field->has_default_value() seems useful, it isn't + // because of enums. proto2 syntax allows the first item in an enum (the + // default) to be non zero. So checking field->has_default_value() would + // result in missing this non zero default. See MessageWithOneBasedEnum in + // objectivec/Tests/unittest_objc.proto for a test Message to confirm this. + + // Some proto file set the default to the zero value, so make sure the value + // isn't the zero case. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return field->default_value_int32() != 0; + case FieldDescriptor::CPPTYPE_UINT32: + return field->default_value_uint32() != 0U; + case FieldDescriptor::CPPTYPE_INT64: + return field->default_value_int64() != 0LL; + case FieldDescriptor::CPPTYPE_UINT64: + return field->default_value_uint64() != 0ULL; + case FieldDescriptor::CPPTYPE_DOUBLE: + return field->default_value_double() != 0.0; + case FieldDescriptor::CPPTYPE_FLOAT: + return field->default_value_float() != 0.0f; + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool(); + case FieldDescriptor::CPPTYPE_STRING: { + const TProtoStringType& default_string = field->default_value_string(); + return default_string.length() != 0; + } + case FieldDescriptor::CPPTYPE_ENUM: + return field->default_value_enum()->number() != 0; + case FieldDescriptor::CPPTYPE_MESSAGE: + return false; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + Y_ABSL_LOG(FATAL) << "Can't get here."; + return false; +} + } // namespace FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) { - FieldGenerator* result = NULL; + FieldGenerator* result = nullptr; if (field->is_repeated()) { switch (GetObjectiveCType(field)) { case OBJECTIVECTYPE_MESSAGE: { @@ -163,16 +221,11 @@ FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor) SetCommonFieldVariables(descriptor, &variables_); } -FieldGenerator::~FieldGenerator() {} - void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const { - printer->Print( - variables_, - "$field_number_name$ = $field_number$,\n"); + printer->Print(variables_, "$field_number_name$ = $field_number$,\n"); } -void FieldGenerator::GenerateCFunctionDeclarations( - io::Printer* printer) const { +void FieldGenerator::GenerateCFunctionDeclarations(io::Printer* printer) const { // Nothing } @@ -182,20 +235,21 @@ void FieldGenerator::GenerateCFunctionImplementations( } void FieldGenerator::DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, + y_absl::btree_set<TProtoStringType>* fwd_decls, bool include_external_types) const { // Nothing } void FieldGenerator::DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) const { + y_absl::btree_set<TProtoStringType>* fwd_decls) const { // Nothing } -void FieldGenerator::GenerateFieldDescription( - io::Printer* printer, bool include_default) const { +void FieldGenerator::GenerateFieldDescription(io::Printer* printer, + bool include_default) const { // Printed in the same order as the structure decl. if (include_default) { + // clang-format off printer->Print( variables_, "{\n" @@ -208,7 +262,9 @@ void FieldGenerator::GenerateFieldDescription( " .core.flags = $fieldflags$,\n" " .core.dataType = GPBDataType$field_type$,\n" "},\n"); + // clang-format on } else { + // clang-format off printer->Print( variables_, "{\n" @@ -220,43 +276,37 @@ void FieldGenerator::GenerateFieldDescription( " .flags = $fieldflags$,\n" " .dataType = GPBDataType$field_type$,\n" "},\n"); + // clang-format on } } void FieldGenerator::SetRuntimeHasBit(int has_index) { - variables_["has_index"] = StrCat(has_index); + variables_["has_index"] = y_absl::StrCat(has_index); } -void FieldGenerator::SetNoHasBit(void) { - variables_["has_index"] = "GPBNoHasBit"; -} +void FieldGenerator::SetNoHasBit() { variables_["has_index"] = "GPBNoHasBit"; } -int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { - return 0; -} +int FieldGenerator::ExtraRuntimeHasBitsNeeded() const { return 0; } void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) { - // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some - // error cases, so it seems to be ok to use as a back door for errors. - std::cerr << "Error: should have overridden SetExtraRuntimeHasBitsBase()." << std::endl; - std::cerr.flush(); - abort(); + Y_ABSL_LOG(FATAL) + << "Error: should have overridden SetExtraRuntimeHasBitsBase()."; } void FieldGenerator::SetOneofIndexBase(int index_base) { const OneofDescriptor* oneof = descriptor_->real_containing_oneof(); - if (oneof != NULL) { + if (oneof != nullptr) { int index = oneof->index() + index_base; // Flip the sign to mark it as a oneof. - variables_["has_index"] = StrCat(-index); + variables_["has_index"] = y_absl::StrCat(-index); } } -bool FieldGenerator::WantsHasProperty(void) const { +bool FieldGenerator::WantsHasProperty() const { return descriptor_->has_presence() && !descriptor_->real_containing_oneof(); } -void FieldGenerator::FinishInitialization(void) { +void FieldGenerator::FinishInitialization() { // If "property_type" wasn't set, make it "storage_type". if ((variables_.find("property_type") == variables_.end()) && (variables_.find("storage_type") != variables_.end())) { @@ -269,8 +319,6 @@ SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor) // Nothing } -SingleFieldGenerator::~SingleFieldGenerator() {} - void SingleFieldGenerator::GenerateFieldStorageDeclaration( io::Printer* printer) const { printer->Print(variables_, "$storage_type$ $name$;\n"); @@ -279,15 +327,19 @@ void SingleFieldGenerator::GenerateFieldStorageDeclaration( void SingleFieldGenerator::GeneratePropertyDeclaration( io::Printer* printer) const { printer->Print(variables_, "$comments$"); + // clang-format off printer->Print( variables_, - "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n" - "\n"); + "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n"); + // clang-format on if (WantsHasProperty()) { + // clang-format off printer->Print( variables_, "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); + // clang-format on } + printer->Print("\n"); } void SingleFieldGenerator::GeneratePropertyImplementation( @@ -299,7 +351,7 @@ void SingleFieldGenerator::GeneratePropertyImplementation( } } -bool SingleFieldGenerator::RuntimeUsesHasBit(void) const { +bool SingleFieldGenerator::RuntimeUsesHasBit() const { if (descriptor_->real_containing_oneof()) { // The oneof tracks what is set instead. return false; @@ -315,8 +367,6 @@ ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor) } } -ObjCObjFieldGenerator::~ObjCObjFieldGenerator() {} - void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration( io::Printer* printer) const { printer->Print(variables_, "$storage_type$ *$name$;\n"); @@ -324,26 +374,30 @@ void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration( void ObjCObjFieldGenerator::GeneratePropertyDeclaration( io::Printer* printer) const { - // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that - // it uses pointers and deals with Objective C's rules around storage name + // it uses pointers and deals with Objective-C's rules around storage name // conventions (init*, new*, etc.) printer->Print(variables_, "$comments$"); + // clang-format off printer->Print( variables_, "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"); + // clang-format on if (WantsHasProperty()) { + // clang-format off printer->Print( variables_, "/** Test to see if @c $name$ has been set. */\n" "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); + // clang-format on } if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 printer->Print(variables_, - "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); + "- ($property_type$ *)$name$ " + "GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); } printer->Print("\n"); } @@ -355,9 +409,7 @@ RepeatedFieldGenerator::RepeatedFieldGenerator( variables_["array_comment"] = ""; } -RepeatedFieldGenerator::~RepeatedFieldGenerator() {} - -void RepeatedFieldGenerator::FinishInitialization(void) { +void RepeatedFieldGenerator::FinishInitialization() { FieldGenerator::FinishInitialization(); if (variables_.find("array_property_type") == variables_.end()) { variables_["array_property_type"] = variable("array_storage_type"); @@ -376,30 +428,33 @@ void RepeatedFieldGenerator::GeneratePropertyImplementation( void RepeatedFieldGenerator::GeneratePropertyDeclaration( io::Printer* printer) const { - // Repeated fields don't need the has* properties, but they do expose a // *Count (to check without autocreation). So for the field property we need // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for - // dealing with needing Objective C's rules around storage name conventions + // dealing with needing Objective-C's rules around storage name conventions // (init*, new*, etc.) + // clang-format off printer->Print( variables_, "$comments$" "$array_comment$" "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n" - "/** The number of items in @c $name$ without causing the array to be created. */\n" + "/** The number of items in @c $name$ without causing the container to be created. */\n" "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n"); + // clang-format on if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 + // clang-format off printer->Print(variables_, "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); + // clang-format on } printer->Print("\n"); } -bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const { +bool RepeatedFieldGenerator::RuntimeUsesHasBit() const { return false; // The array (or map/dict) having anything is what is used. } @@ -409,8 +464,7 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) extension_generators_(descriptor->extension_count()) { // Construct all the FieldGenerators. for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset( - FieldGenerator::Make(descriptor->field(i))); + field_generators_[i].reset(FieldGenerator::Make(descriptor->field(i))); } for (int i = 0; i < descriptor->extension_count(); i++) { extension_generators_[i].reset( @@ -418,11 +472,9 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) } } -FieldGeneratorMap::~FieldGeneratorMap() {} - const FieldGenerator& FieldGeneratorMap::get( const FieldDescriptor* field) const { - GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + Y_ABSL_CHECK_EQ(field->containing_type(), descriptor_); return *field_generators_[field->index()]; } @@ -430,7 +482,7 @@ const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { return *extension_generators_[index]; } -int FieldGeneratorMap::CalculateHasBits(void) { +int FieldGeneratorMap::CalculateHasBits() { int total_bits = 0; for (int i = 0; i < descriptor_->field_count(); i++) { if (field_generators_[i]->RuntimeUsesHasBit()) { @@ -454,7 +506,7 @@ void FieldGeneratorMap::SetOneofIndexBase(int index_base) { } } -bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const { +bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault() const { for (int i = 0; i < descriptor_->field_count(); i++) { if (HasNonZeroDefaultValue(descriptor_->field(i))) { return true; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/field.h index 3e968946fa..0450065133 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/field.h @@ -31,10 +31,15 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__ -#include <map> +#include <memory> #include <string> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/io/printer.h> +#include <vector> + +#include "y_absl/container/btree_set.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/strings/match.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -45,7 +50,7 @@ class FieldGenerator { public: static FieldGenerator* Make(const FieldDescriptor* field); - virtual ~FieldGenerator(); + virtual ~FieldGenerator() = default; FieldGenerator(const FieldGenerator&) = delete; FieldGenerator& operator=(const FieldGenerator&) = delete; @@ -64,21 +69,21 @@ class FieldGenerator { // Exposed for subclasses, should always call it on the parent class also. virtual void DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, + y_absl::btree_set<TProtoStringType>* fwd_decls, bool include_external_types) const; virtual void DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) const; + y_absl::btree_set<TProtoStringType>* fwd_decls) const; // Used during generation, not intended to be extended by subclasses. - void GenerateFieldDescription( - io::Printer* printer, bool include_default) const; + void GenerateFieldDescription(io::Printer* printer, + bool include_default) const; void GenerateFieldNumberConstant(io::Printer* printer) const; // Exposed to get and set the has bits information. - virtual bool RuntimeUsesHasBit(void) const = 0; + virtual bool RuntimeUsesHasBit() const = 0; void SetRuntimeHasBit(int has_index); - void SetNoHasBit(void); - virtual int ExtraRuntimeHasBitsNeeded(void) const; + void SetNoHasBit(); + virtual int ExtraRuntimeHasBitsNeeded() const; virtual void SetExtraRuntimeHasBitsBase(int index_base); void SetOneofIndexBase(int index_base); @@ -88,8 +93,7 @@ class FieldGenerator { bool needs_textformat_name_support() const { const TProtoStringType& field_flags = variable("fieldflags"); - return field_flags.find("GPBFieldTextFormatNameCustom") != - TProtoStringType::npos; + return y_absl::StrContains(field_flags, "GPBFieldTextFormatNameCustom"); } TProtoStringType generated_objc_name() const { return variable("name"); } TProtoStringType raw_field_name() const { return variable("raw_field_name"); } @@ -97,26 +101,26 @@ class FieldGenerator { protected: explicit FieldGenerator(const FieldDescriptor* descriptor); - virtual void FinishInitialization(void); - bool WantsHasProperty(void) const; + virtual void FinishInitialization(); + bool WantsHasProperty() const; const FieldDescriptor* descriptor_; - std::map<TProtoStringType, TProtoStringType> variables_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> variables_; }; class SingleFieldGenerator : public FieldGenerator { public: - virtual ~SingleFieldGenerator(); + ~SingleFieldGenerator() override = default; SingleFieldGenerator(const SingleFieldGenerator&) = delete; SingleFieldGenerator& operator=(const SingleFieldGenerator&) = delete; - virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; - virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; + void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + void GeneratePropertyDeclaration(io::Printer* printer) const override; - virtual void GeneratePropertyImplementation(io::Printer* printer) const override; + void GeneratePropertyImplementation(io::Printer* printer) const override; - virtual bool RuntimeUsesHasBit(void) const override; + bool RuntimeUsesHasBit() const override; protected: explicit SingleFieldGenerator(const FieldDescriptor* descriptor); @@ -125,13 +129,13 @@ class SingleFieldGenerator : public FieldGenerator { // Subclass with common support for when the field ends up as an ObjC Object. class ObjCObjFieldGenerator : public SingleFieldGenerator { public: - virtual ~ObjCObjFieldGenerator(); + ~ObjCObjFieldGenerator() override = default; ObjCObjFieldGenerator(const ObjCObjFieldGenerator&) = delete; ObjCObjFieldGenerator& operator=(const ObjCObjFieldGenerator&) = delete; - virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; - virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; + void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + void GeneratePropertyDeclaration(io::Printer* printer) const override; protected: explicit ObjCObjFieldGenerator(const FieldDescriptor* descriptor); @@ -139,28 +143,28 @@ class ObjCObjFieldGenerator : public SingleFieldGenerator { class RepeatedFieldGenerator : public ObjCObjFieldGenerator { public: - virtual ~RepeatedFieldGenerator(); + ~RepeatedFieldGenerator() override = default; RepeatedFieldGenerator(const RepeatedFieldGenerator&) = delete; RepeatedFieldGenerator& operator=(const RepeatedFieldGenerator&) = delete; - virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; - virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; + void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + void GeneratePropertyDeclaration(io::Printer* printer) const override; - virtual void GeneratePropertyImplementation(io::Printer* printer) const override; + void GeneratePropertyImplementation(io::Printer* printer) const override; - virtual bool RuntimeUsesHasBit(void) const override; + bool RuntimeUsesHasBit() const override; protected: explicit RepeatedFieldGenerator(const FieldDescriptor* descriptor); - virtual void FinishInitialization(void) override; + void FinishInitialization() override; }; // Convenience class which constructs FieldGenerators for a Descriptor. class FieldGeneratorMap { public: explicit FieldGeneratorMap(const Descriptor* descriptor); - ~FieldGeneratorMap(); + ~FieldGeneratorMap() = default; FieldGeneratorMap(const FieldGeneratorMap&) = delete; FieldGeneratorMap& operator=(const FieldGeneratorMap&) = delete; @@ -169,12 +173,12 @@ class FieldGeneratorMap { const FieldGenerator& get_extension(int index) const; // Assigns the has bits and returns the number of bits needed. - int CalculateHasBits(void); + int CalculateHasBits(); void SetOneofIndexBase(int index_base); // Check if any field of this message has a non zero default. - bool DoesAnyFieldHaveNonZeroDefault(void) const; + bool DoesAnyFieldHaveNonZeroDefault() const; private: const Descriptor* descriptor_; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/file.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/file.cc new file mode 100644 index 0000000000..06be7c9cec --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/file.cc @@ -0,0 +1,736 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/file.h" + +#include <algorithm> +#include <functional> +#include <iostream> +#include <iterator> +#include <memory> +#include <sstream> +#include <string> +#include <vector> + +#include "y_absl/container/btree_set.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/str_join.h" +#include "google/protobuf/compiler/objectivec/enum.h" +#include "google/protobuf/compiler/objectivec/extension.h" +#include "google/protobuf/compiler/objectivec/import_writer.h" +#include "google/protobuf/compiler/objectivec/message.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/printer.h" + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +// This is also found in GPBBootstrap.h, and needs to be kept in sync. +const arc_i32 GOOGLE_PROTOBUF_OBJC_VERSION = 30007; + +const char* kHeaderExtension = ".pbobjc.h"; + +// Checks if a message contains any extension definitions (on the message or +// a nested message under it). +bool MessageContainsExtensions(const Descriptor* message) { + if (message->extension_count() > 0) { + return true; + } + for (int i = 0; i < message->nested_type_count(); i++) { + if (MessageContainsExtensions(message->nested_type(i))) { + return true; + } + } + return false; +} + +// Checks if the file contains any extensions definitions (at the root or +// nested under a message). +bool FileContainsExtensions(const FileDescriptor* file) { + if (file->extension_count() > 0) { + return true; + } + for (int i = 0; i < file->message_type_count(); i++) { + if (MessageContainsExtensions(file->message_type(i))) { + return true; + } + } + return false; +} + +bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) { + for (int i = 0; i < file->dependency_count(); i++) { + if (dep == file->dependency(i)) { + return true; + } + } + return false; +} + +struct FileDescriptorsOrderedByName { + inline bool operator()(const FileDescriptor* a, + const FileDescriptor* b) const { + return a->name() < b->name(); + } +}; + +void MakeDescriptors( + const Descriptor* descriptor, const TProtoStringType& file_description_name, + std::vector<std::unique_ptr<EnumGenerator>>* enum_generators, + std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators, + std::vector<std::unique_ptr<MessageGenerator>>* message_generators) { + for (int i = 0; i < descriptor->enum_type_count(); i++) { + enum_generators->emplace_back( + std::make_unique<EnumGenerator>(descriptor->enum_type(i))); + } + for (int i = 0; i < descriptor->nested_type_count(); i++) { + message_generators->emplace_back(std::make_unique<MessageGenerator>( + file_description_name, descriptor->nested_type(i))); + message_generators->back()->AddExtensionGenerators(extension_generators); + MakeDescriptors(descriptor->nested_type(i), file_description_name, + enum_generators, extension_generators, message_generators); + } +} + +} // namespace + +const FileGenerator::CommonState::MinDepsEntry& +FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensionsInternal( + const FileDescriptor* file) { + auto it = deps_info_cache.find(file); + if (it != deps_info_cache.end()) { + return it->second; + } + + y_absl::flat_hash_set<const FileDescriptor*> min_deps_collector; + y_absl::flat_hash_set<const FileDescriptor*> transitive_deps_collector; + y_absl::flat_hash_set<const FileDescriptor*> to_prune; + for (int i = 0; i < file->dependency_count(); i++) { + const FileDescriptor* dep = file->dependency(i); + MinDepsEntry dep_info = + CollectMinimalFileDepsContainingExtensionsInternal(dep); + + // Everything the dep covered, this file will also cover. + transitive_deps_collector.insert(dep_info.transitive_deps.begin(), + dep_info.transitive_deps.end()); + // Prune everything from the dep's covered list in case another dep lists it + // as a min dep. + to_prune.insert(dep_info.transitive_deps.begin(), + dep_info.transitive_deps.end()); + + // Does the dep have any extensions... + if (dep_info.has_extensions) { + // Yes -> Add this file, prune its min_deps and add them to the covered + // deps. + min_deps_collector.insert(dep); + to_prune.insert(dep_info.min_deps.begin(), dep_info.min_deps.end()); + transitive_deps_collector.insert(dep_info.min_deps.begin(), + dep_info.min_deps.end()); + } else { + // No -> Just use its min_deps. + min_deps_collector.insert(dep_info.min_deps.begin(), + dep_info.min_deps.end()); + } + } + + const bool file_has_exts = FileContainsExtensions(file); + + // Fast path: if nothing to prune or there was only one dep, the prune work is + // a waste, skip it. + if (to_prune.empty() || file->dependency_count() == 1) { + return deps_info_cache + .insert( + {file, + {file_has_exts, min_deps_collector, transitive_deps_collector}}) + .first->second; + } + + y_absl::flat_hash_set<const FileDescriptor*> min_deps; + std::copy_if(min_deps_collector.begin(), min_deps_collector.end(), + std::inserter(min_deps, min_deps.begin()), + [&](const FileDescriptor* value) { + return to_prune.find(value) == to_prune.end(); + }); + return deps_info_cache + .insert({file, {file_has_exts, min_deps, transitive_deps_collector}}) + .first->second; +} + +// Collect the deps of the given file that contain extensions. This can be used +// to create the chain of roots that need to be wired together. +// +// NOTE: If any changes are made to this and the supporting functions, you will +// need to manually validate what the generated code is for the test files: +// objectivec/Tests/unittest_extension_chain_*.proto +// There are comments about what the expected code should be line and limited +// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports +// specifically). +std::vector<const FileDescriptor*> +FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensions( + const FileDescriptor* file) { + y_absl::flat_hash_set<const FileDescriptor*> min_deps = + CollectMinimalFileDepsContainingExtensionsInternal(file).min_deps; + // Sort the list since pointer order isn't stable across runs. + std::vector<const FileDescriptor*> result(min_deps.begin(), min_deps.end()); + std::sort(result.begin(), result.end(), FileDescriptorsOrderedByName()); + return result; +} + +FileGenerator::FileGenerator(const FileDescriptor* file, + const GenerationOptions& generation_options, + CommonState& common_state) + : file_(file), + generation_options_(generation_options), + common_state_(&common_state), + root_class_name_(FileClassName(file)), + file_description_name_(FileClassName(file) + "_FileDescription"), + is_bundled_proto_(IsProtobufLibraryBundledProtoFile(file)) { + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_.emplace_back( + std::make_unique<EnumGenerator>(file_->enum_type(i))); + } + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_.push_back(std::make_unique<ExtensionGenerator>( + root_class_name_, file_->extension(i))); + } + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_.emplace_back(std::make_unique<MessageGenerator>( + file_description_name_, file_->message_type(i))); + message_generators_.back()->AddExtensionGenerators(&extension_generators_); + MakeDescriptors(file_->message_type(i), file_description_name_, + &enum_generators_, &extension_generators_, + &message_generators_); + } +} + +void FileGenerator::GenerateHeader(io::Printer* p) const { + GenerateFile(p, GeneratedFileType::kHeader, [&] { + p->Print("CF_EXTERN_C_BEGIN\n\n"); + + y_absl::btree_set<TProtoStringType> fwd_decls; + for (const auto& generator : message_generators_) { + generator->DetermineForwardDeclarations(&fwd_decls, + /* include_external_types = */ + HeadersUseForwardDeclarations()); + } + if (!fwd_decls.empty()) { + p->Print("$fwd_decls$\n\n", "fwd_decls", y_absl::StrJoin(fwd_decls, "\n")); + } + + p->Print("NS_ASSUME_NONNULL_BEGIN\n\n"); + + for (const auto& generator : enum_generators_) { + generator->GenerateHeader(p); + } + + // For extensions to chain together, the Root gets created even if there + // are no extensions. + p->Print( + // clang-format off + "#pragma mark - $root_class_name$\n" + "\n" + "/**\n" + " * Exposes the extension registry for this file.\n" + " *\n" + " * The base class provides:\n" + " * @code\n" + " * + (GPBExtensionRegistry *)extensionRegistry;\n" + " * @endcode\n" + " * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n" + " * this file and all files that it depends on.\n" + " **/\n" + "GPB_FINAL @interface $root_class_name$ : GPBRootObject\n" + "@end\n" + "\n", + // clang-format on + "root_class_name", root_class_name_); + + // The dynamic methods block is only needed if there are extensions that are + // file level scoped (not message scoped). The first + // file_->extension_count() of extension_generators_ are the file scoped + // ones. + if (file_->extension_count()) { + p->Print("@interface $root_class_name$ (DynamicMethods)\n", + "root_class_name", root_class_name_); + + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateMembersHeader(p); + } + + p->Print("@end\n\n"); + } // file_->extension_count() + + for (const auto& generator : message_generators_) { + generator->GenerateMessageHeader(p); + } + + // clang-format off + p->Print( + "NS_ASSUME_NONNULL_END\n" + "\n" + "CF_EXTERN_C_END\n"); + // clang-format on + }); +} + +void FileGenerator::GenerateSource(io::Printer* p) const { + std::vector<const FileDescriptor*> deps_with_extensions = + common_state_->CollectMinimalFileDepsContainingExtensions(file_); + GeneratedFileOptions file_options; + + // If any indirect dependency provided extensions, it needs to be directly + // imported so it can get merged into the root's extensions registry. + // See the Note by CollectMinimalFileDepsContainingExtensions before + // changing this. + for (auto& dep : deps_with_extensions) { + if (!IsDirectDependency(dep, file_)) { + file_options.extra_files_to_import.push_back(dep); + } + } + + y_absl::btree_set<TProtoStringType> fwd_decls; + for (const auto& generator : message_generators_) { + generator->DetermineObjectiveCClassDefinitions(&fwd_decls); + } + for (const auto& generator : extension_generators_) { + generator->DetermineObjectiveCClassDefinitions(&fwd_decls); + } + + // The generated code for oneof's uses direct ivar access, suppress the + // warning in case developer turn that on in the context they compile the + // generated code. + for (const auto& generator : message_generators_) { + if (generator->IncludesOneOfDefinition()) { + file_options.ignored_warnings.push_back("direct-ivar-access"); + break; + } + } + if (!fwd_decls.empty()) { + file_options.ignored_warnings.push_back("dollar-in-identifier-extension"); + } + + // Enum implementation uses atomic in the generated code, so add + // the system import as needed. + if (!enum_generators_.empty()) { + file_options.extra_system_headers.push_back("stdatomic.h"); + } + + GenerateFile(p, GeneratedFileType::kSource, file_options, [&] { + if (!fwd_decls.empty()) { + p->Print( + // clang-format off + "#pragma mark - Objective-C Class declarations\n" + "// Forward declarations of Objective-C classes that we can use as\n" + "// static values in struct initializers.\n" + "// We don't use [Foo class] because it is not a static value.\n" + "$fwd_decls$\n" + "\n", + // clang-format on + "fwd_decls", y_absl::StrJoin(fwd_decls, "\n")); + } + + PrintRootImplementation(p, deps_with_extensions); + PrintFileDescription(p); + + for (const auto& generator : enum_generators_) { + generator->GenerateSource(p); + } + for (const auto& generator : message_generators_) { + generator->GenerateSource(p); + } + }); +} + +void FileGenerator::GenerateGlobalSource(io::Printer* p) const { + std::vector<const FileDescriptor*> deps_with_extensions = + common_state_->CollectMinimalFileDepsContainingExtensions(file_); + GeneratedFileOptions file_options; + + // If any indirect dependency provided extensions, it needs to be directly + // imported so it can get merged into the root's extensions registry. + // See the Note by CollectMinimalFileDepsContainingExtensions before + // changing this. + for (auto& dep : deps_with_extensions) { + if (!IsDirectDependency(dep, file_)) { + file_options.extra_files_to_import.push_back(dep); + } + } + + y_absl::btree_set<TProtoStringType> fwd_decls; + for (const auto& generator : extension_generators_) { + generator->DetermineObjectiveCClassDefinitions(&fwd_decls); + } + + if (!fwd_decls.empty()) { + file_options.ignored_warnings.push_back("dollar-in-identifier-extension"); + } + + GenerateFile(p, GeneratedFileType::kSource, file_options, [&] { + if (!fwd_decls.empty()) { + p->Print( + // clang-format off + "#pragma mark - Objective-C Class declarations\n" + "// Forward declarations of Objective-C classes that we can use as\n" + "// static values in struct initializers.\n" + "// We don't use [Foo class] because it is not a static value.\n" + "$fwd_decls$\n" + "\n", + // clang-format on + "fwd_decls", y_absl::StrJoin(fwd_decls, "\n")); + } + + PrintRootImplementation(p, deps_with_extensions); + }); +} + +void FileGenerator::GenerateSourceForEnums(io::Printer* p) const { + // Enum implementation uses atomic in the generated code. + GeneratedFileOptions file_options; + file_options.extra_system_headers.push_back("stdatomic.h"); + + GenerateFile(p, GeneratedFileType::kSource, file_options, [&] { + for (const auto& generator : enum_generators_) { + generator->GenerateSource(p); + } + }); +} + +void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* p) const { + const auto& generator = message_generators_[idx]; + + y_absl::btree_set<TProtoStringType> fwd_decls; + generator->DetermineObjectiveCClassDefinitions(&fwd_decls); + + GeneratedFileOptions file_options; + // The generated code for oneof's uses direct ivar access, suppress the + // warning in case developer turn that on in the context they compile the + // generated code. + if (generator->IncludesOneOfDefinition()) { + file_options.ignored_warnings.push_back("direct-ivar-access"); + } + + GenerateFile(p, GeneratedFileType::kSource, file_options, [&] { + if (!fwd_decls.empty()) { + p->Print( + // clang-format off + "#pragma mark - Objective-C Class declarations\n" + "// Forward declarations of Objective-C classes that we can use as\n" + "// static values in struct initializers.\n" + "// We don't use [Foo class] because it is not a static value.\n" + "$fwd_decls$\n" + "\n", + // clang-format on + "fwd_decls", y_absl::StrJoin(fwd_decls, "\n")); + } + + PrintFileDescription(p); + generator->GenerateSource(p); + }); +} + +void FileGenerator::GenerateFile(io::Printer* p, GeneratedFileType file_type, + const GeneratedFileOptions& file_options, + std::function<void()> body) const { + ImportWriter import_writer( + generation_options_.generate_for_named_framework, + generation_options_.named_framework_to_proto_path_mappings_path, + generation_options_.runtime_import_prefix, + /* for_bundled_proto = */ is_bundled_proto_); + const TProtoStringType header_extension(kHeaderExtension); + + switch (file_type) { + case GeneratedFileType::kHeader: + // Generated files bundled with the library get minimal imports, + // everything else gets the wrapper so everything is usable. + if (is_bundled_proto_) { + import_writer.AddRuntimeImport("GPBDescriptor.h"); + import_writer.AddRuntimeImport("GPBMessage.h"); + import_writer.AddRuntimeImport("GPBRootObject.h"); + } else { + import_writer.AddRuntimeImport("GPBProtocolBuffers.h"); + } + if (HeadersUseForwardDeclarations()) { + // #import any headers for "public imports" in the proto file. + for (int i = 0; i < file_->public_dependency_count(); i++) { + import_writer.AddFile(file_->public_dependency(i), header_extension); + } + } else { + for (int i = 0; i < file_->dependency_count(); i++) { + import_writer.AddFile(file_->dependency(i), header_extension); + } + } + break; + case GeneratedFileType::kSource: + import_writer.AddRuntimeImport("GPBProtocolBuffers_RuntimeSupport.h"); + import_writer.AddFile(file_, header_extension); + if (HeadersUseForwardDeclarations()) { + // #import the headers for anything that a plain dependency of this + // proto file (that means they were just an include, not a "public" + // include). + y_absl::flat_hash_set<TProtoStringType> public_import_names; + for (int i = 0; i < file_->public_dependency_count(); i++) { + public_import_names.insert(file_->public_dependency(i)->name()); + } + for (int i = 0; i < file_->dependency_count(); i++) { + const FileDescriptor* dep = file_->dependency(i); + if (!public_import_names.contains(dep->name())) { + import_writer.AddFile(dep, header_extension); + } + } + } + break; + } + + for (const auto& dep : file_options.extra_files_to_import) { + import_writer.AddFile(dep, header_extension); + } + + p->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// $clangfmt$ off\n" + "// source: $filename$\n" + "\n", + "filename", file_->name(), "clangfmt", "clang-format"); + + import_writer.PrintRuntimeImports( + p, /* default_cpp_symbol = */ !is_bundled_proto_); + + p->Print("\n"); + + // Add some verification that the generated code matches the source the + // code is being compiled with. + // NOTE: This captures the raw numeric values at the time the generator was + // compiled, since that will be the versions for the ObjC runtime at that + // time. The constants in the generated code will then get their values at + // compile time (so checking against the headers being used to compile). + p->Print( + // clang-format off + "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n" + "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n" + "#endif\n" + "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n" + "#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n" + "#endif\n" + "\n", + // clang-format on + "google_protobuf_objc_version", + y_absl::StrCat(GOOGLE_PROTOBUF_OBJC_VERSION)); + + if (!file_options.extra_system_headers.empty()) { + for (const auto& system_header : file_options.extra_system_headers) { + p->Print("#import <$header$>\n", "header", system_header); + } + p->Print("\n"); + } + + import_writer.PrintFileImports(p); + + // clang-format off + p->Print( + "// @@protoc_insertion_point(imports)\n" + "\n" + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"); + // clang-format on + for (const auto& warning : file_options.ignored_warnings) { + p->Print("#pragma clang diagnostic ignored \"-W$warning$\"\n", "warning", + warning); + } + p->Print("\n"); + + body(); + + p->Print( + "\n" + "#pragma clang diagnostic pop\n" + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n" + "// $clangfmt$ on\n", + "clangfmt", "clang-format"); +} + +void FileGenerator::PrintRootImplementation( + io::Printer* p, + const std::vector<const FileDescriptor*>& deps_with_extensions) const { + p->Print( + // clang-format off + "#pragma mark - $root_class_name$\n" + "\n" + "@implementation $root_class_name$\n" + "\n", + // clang-format on + "root_class_name", root_class_name_); + + // If there were any extensions or this file has any dependencies, output a + // registry to override to create the file specific registry. + if (extension_generators_.empty() && deps_with_extensions.empty()) { + if (file_->dependency_count() == 0) { + // clang-format off + p->Print( + "// No extensions in the file and no imports, so no need to generate\n" + "// +extensionRegistry.\n"); + // clang-format on + } else { + // clang-format off + p->Print( + "// No extensions in the file and none of the imports (direct or indirect)\n" + "// defined extensions, so no need to generate +extensionRegistry.\n"); + // clang-format on + } + } else { + PrintRootExtensionRegistryImplementation(p, deps_with_extensions); + } + + p->Print("\n@end\n\n"); +} + +void FileGenerator::PrintRootExtensionRegistryImplementation( + io::Printer* p, + const std::vector<const FileDescriptor*>& deps_with_extensions) const { + // clang-format off + p->Print( + "+ (GPBExtensionRegistry*)extensionRegistry {\n" + " // This is called by +initialize so there is no need to worry\n" + " // about thread safety and initialization of registry.\n" + " static GPBExtensionRegistry* registry = nil;\n" + " if (!registry) {\n" + " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n" + " registry = [[GPBExtensionRegistry alloc] init];\n"); + // clang-format on + + p->Indent(); + p->Indent(); + + if (!extension_generators_.empty()) { + p->Print("static GPBExtensionDescription descriptions[] = {\n"); + p->Indent(); + for (const auto& generator : extension_generators_) { + generator->GenerateStaticVariablesInitialization(p); + } + p->Outdent(); + // clang-format off + p->Print( + "};\n" + "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n" + " GPBExtensionDescriptor *extension =\n" + " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]\n" + " usesClassRefs:YES];\n" + " [registry addExtension:extension];\n" + " [self globallyRegisterExtension:extension];\n" + " [extension release];\n" + "}\n"); + // clang-format on + } + + if (deps_with_extensions.empty()) { + // clang-format off + p->Print( + "// None of the imports (direct or indirect) defined extensions, so no need to add\n" + "// them to this registry.\n"); + // clang-format on + } else { + // clang-format off + p->Print( + "// Merge in the imports (direct or indirect) that defined extensions.\n"); + // clang-format on + for (const auto& dep : deps_with_extensions) { + const TProtoStringType root_class_name(FileClassName((dep))); + p->Print("[registry addExtensions:[$dependency$ extensionRegistry]];\n", + "dependency", root_class_name); + } + } + + p->Outdent(); + p->Outdent(); + + // clang-format off + p->Print( + " }\n" + " return registry;\n" + "}\n"); + // clang-format on +} + +void FileGenerator::PrintFileDescription(io::Printer* p) const { + // File descriptor only needed if there are messages to use it. + if (message_generators_.empty()) { + return; + } + + const TProtoStringType objc_prefix(FileClassPrefix(file_)); + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars; + vars["file_description_name"] = file_description_name_; + vars["package_value"] = file_->package().empty() + ? "NULL" + : y_absl::StrCat("\"", file_->package(), "\""); + switch (file_->syntax()) { + case FileDescriptor::SYNTAX_UNKNOWN: + vars["syntax"] = "GPBFileSyntaxUnknown"; + break; + case FileDescriptor::SYNTAX_PROTO2: + vars["syntax"] = "GPBFileSyntaxProto2"; + break; + case FileDescriptor::SYNTAX_PROTO3: + vars["syntax"] = "GPBFileSyntaxProto3"; + break; + } + if (objc_prefix.empty() && !file_->options().has_objc_class_prefix()) { + vars["prefix_value"] = "NULL"; + } else { + vars["prefix_value"] = y_absl::StrCat("\"", objc_prefix, "\""); + } + + // clang-format off + p->Print( + vars, + "static GPBFileDescription $file_description_name$ = {\n" + " .package = $package_value$,\n" + " .prefix = $prefix_value$,\n" + " .syntax = $syntax$\n" + "};\n" + "\n"); + // clang-format on +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/file.h index de37930eb3..e83c27c2ec 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/file.h @@ -31,80 +31,108 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__ -#include <map> -#include <set> +#include <functional> +#include <memory> #include <string> #include <vector> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/io/printer.h> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/container/flat_hash_set.h" +#include "google/protobuf/compiler/objectivec/enum.h" +#include "google/protobuf/compiler/objectivec/extension.h" +#include "google/protobuf/compiler/objectivec/message.h" +#include "google/protobuf/compiler/objectivec/options.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace objectivec { -class EnumGenerator; -class ExtensionGenerator; -class MessageGenerator; - class FileGenerator { public: - struct GenerationOptions { - GenerationOptions() - // TODO(thomasvl): Eventually flip this default to false for better - // interop with Swift if proto usages span modules made from ObjC sources. - : headers_use_forward_declarations(true) {} - TProtoStringType generate_for_named_framework; - TProtoStringType named_framework_to_proto_path_mappings_path; - TProtoStringType runtime_import_prefix; - bool headers_use_forward_declarations; - }; - // Wrapper for some common state that is shared between file generations to // improve performance when more than one file is generated at a time. struct CommonState { - CommonState(); + CommonState() = default; - const std::vector<const FileDescriptor*> + std::vector<const FileDescriptor*> CollectMinimalFileDepsContainingExtensions(const FileDescriptor* file); private: struct MinDepsEntry { bool has_extensions; - std::set<const FileDescriptor*> min_deps; - // `covered_deps` are the transtive deps of `min_deps_w_exts` that also - // have extensions. - std::set<const FileDescriptor*> covered_deps; + // The minimal dependencies that cover all the dependencies with + // extensions. + y_absl::flat_hash_set<const FileDescriptor*> min_deps; + y_absl::flat_hash_set<const FileDescriptor*> transitive_deps; }; - const MinDepsEntry& CollectMinimalFileDepsContainingExtensionsInternal(const FileDescriptor* file); - std::map<const FileDescriptor*, MinDepsEntry> deps_info_cache_; + const MinDepsEntry& CollectMinimalFileDepsContainingExtensionsInternal( + const FileDescriptor* file); + y_absl::flat_hash_map<const FileDescriptor*, MinDepsEntry> deps_info_cache; }; FileGenerator(const FileDescriptor* file, const GenerationOptions& generation_options, CommonState& common_state); - ~FileGenerator(); + ~FileGenerator() = default; FileGenerator(const FileGenerator&) = delete; FileGenerator& operator=(const FileGenerator&) = delete; - void GenerateSource(io::Printer* printer); - void GenerateHeader(io::Printer* printer); + void GenerateHeader(io::Printer* p) const; + void GenerateSource(io::Printer* p) const; + + int NumEnums() const { return enum_generators_.size(); } + int NumMessages() const { return message_generators_.size(); } + + void GenerateGlobalSource(io::Printer* p) const; + void GenerateSourceForMessage(int idx, io::Printer* p) const; + void GenerateSourceForEnums(io::Printer* p) const; private: + enum class GeneratedFileType : int { kHeader, kSource }; + struct GeneratedFileOptions { + std::vector<TProtoStringType> ignored_warnings; + std::vector<const FileDescriptor*> extra_files_to_import; + std::vector<TProtoStringType> extra_system_headers; + }; + + void GenerateFile(io::Printer* p, GeneratedFileType file_type, + const GeneratedFileOptions& file_options, + std::function<void()> body) const; + void GenerateFile(io::Printer* p, GeneratedFileType file_type, + std::function<void()> body) const { + GeneratedFileOptions file_options; + GenerateFile(p, file_type, file_options, body); + } + + void PrintRootImplementation( + io::Printer* p, + const std::vector<const FileDescriptor*>& deps_with_extensions) const; + void PrintRootExtensionRegistryImplementation( + io::Printer* p, + const std::vector<const FileDescriptor*>& deps_with_extensions) const; + void PrintFileDescription(io::Printer* p) const; + + bool HeadersUseForwardDeclarations() const { + // The bundled protos (WKTs) don't make use of forward declarations. + return !is_bundled_proto_ && + generation_options_.headers_use_forward_declarations; + } + const FileDescriptor* file_; const GenerationOptions& generation_options_; - CommonState& common_state_; - TProtoStringType root_class_name_; - bool is_bundled_proto_; + mutable CommonState* common_state_; + const TProtoStringType root_class_name_; + const TProtoStringType file_description_name_; + const bool is_bundled_proto_; std::vector<std::unique_ptr<EnumGenerator>> enum_generators_; std::vector<std::unique_ptr<MessageGenerator>> message_generators_; + // The first file_->extension_count() are the extensions at file level scope. std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_; - - void PrintFileRuntimePreamble( - io::Printer* printer, - const std::vector<TProtoStringType>& headers_to_import) const; }; } // namespace objectivec diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/generator.cc index 586cdb025b..31c99dba67 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_generator.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/generator.cc @@ -28,16 +28,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "google/protobuf/compiler/objectivec/generator.h" + #include <fstream> #include <iostream> +#include <memory> #include <string> -#include <unordered_set> -#include <google/protobuf/compiler/objectivec/objectivec_generator.h> -#include <google/protobuf/compiler/objectivec/objectivec_file.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/stubs/strutil.h> +#include <utility> +#include <vector> + +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/str_split.h" +#include "y_absl/strings/strip.h" +#include "google/protobuf/compiler/objectivec/file.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/io/zero_copy_stream.h" namespace google { namespace protobuf { @@ -47,16 +55,17 @@ namespace objectivec { namespace { // Convert a string with "yes"/"no" (case insensitive) to a boolean, returning -// true/false for if the input string was a valid value. If the input string is -// invalid, `result` is unchanged. +// true/false for if the input string was a valid value. The empty string is +// also treated as a true value. If the input string is invalid, `result` is +// unchanged. bool StringToBool(const TProtoStringType& value, bool* result) { TProtoStringType upper_value(value); - UpperString(&upper_value); + y_absl::AsciiStrToUpper(&upper_value); if (upper_value == "NO") { *result = false; return true; } - if (upper_value == "YES") { + if (upper_value == "YES" || upper_value.empty()) { *result = true; return true; } @@ -64,15 +73,13 @@ bool StringToBool(const TProtoStringType& value, bool* result) { return false; } -} // namespace +TProtoStringType NumberedObjCMFileName(y_absl::string_view basename, int number) { + return y_absl::StrCat(basename, ".out/", number, ".pbobjc.m"); +} -ObjectiveCGenerator::ObjectiveCGenerator() {} +} // namespace -ObjectiveCGenerator::~ObjectiveCGenerator() {} - -bool ObjectiveCGenerator::HasGenerateAll() const { - return true; -} +bool ObjectiveCGenerator::HasGenerateAll() const { return true; } bool ObjectiveCGenerator::Generate(const FileDescriptor* file, const TProtoStringType& parameter, @@ -92,14 +99,15 @@ bool ObjectiveCGenerator::GenerateAll( // options along with their values. If the option appears multiple times, only // the last value will be considered. // - // e.g. protoc ... --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework + // e.g. protoc ... + // --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework Options validation_options; - FileGenerator::GenerationOptions generation_options; + GenerationOptions generation_options; std::vector<std::pair<TProtoStringType, TProtoStringType> > options; ParseGeneratorParameter(parameter, &options); - for (int i = 0; i < options.size(); i++) { + for (size_t i = 0; i < options.size(); i++) { if (options[i].first == "expected_prefixes_path") { // Path to find a file containing the expected prefixes // (objc_class_prefix "PREFIX") for proto packages (package NAME). The @@ -122,8 +130,8 @@ bool ObjectiveCGenerator::GenerateAll( // A semicolon delimited string that lists the paths of .proto files to // exclude from the package prefix validations (expected_prefixes_path). // This is provided as an "out", to skip some files being checked. - for (StringPiece split_piece : Split( - options[i].second, ";", true)) { + for (y_absl::string_view split_piece : + y_absl::StrSplit(options[i].second, ';', y_absl::SkipEmpty())) { validation_options.expected_prefixes_suppressions.push_back( TProtoStringType(split_piece)); } @@ -137,7 +145,9 @@ bool ObjectiveCGenerator::GenerateAll( // Default is "no". if (!StringToBool(options[i].second, &validation_options.prefixes_must_be_registered)) { - *error = "error: Unknown value for prefixes_must_be_registered: " + options[i].second; + *error = y_absl::StrCat( + "error: Unknown value for prefixes_must_be_registered: ", + options[i].second); return false; } } else if (options[i].first == "require_prefixes") { @@ -149,7 +159,8 @@ bool ObjectiveCGenerator::GenerateAll( // Default is "no". if (!StringToBool(options[i].second, &validation_options.require_prefixes)) { - *error = "error: Unknown value for require_prefixes: " + options[i].second; + *error = y_absl::StrCat("error: Unknown value for require_prefixes: ", + options[i].second); return false; } } else if (options[i].first == "generate_for_named_framework") { @@ -162,7 +173,8 @@ bool ObjectiveCGenerator::GenerateAll( // the "default" framework name used for everything that wasn't mapped by // the mapping file. generation_options.generate_for_named_framework = options[i].second; - } else if (options[i].first == "named_framework_to_proto_path_mappings_path") { + } else if (options[i].first == + "named_framework_to_proto_path_mappings_path") { // Path to find a file containing the list of framework names and proto // files. The generator uses this to decide if a proto file // referenced should use a framework style import vs. a user level import @@ -183,17 +195,20 @@ bool ObjectiveCGenerator::GenerateAll( // mappings file, it will use the default framework name if one was passed // with generate_for_named_framework, or the relative path to it's include // path otherwise. - generation_options.named_framework_to_proto_path_mappings_path = options[i].second; + generation_options.named_framework_to_proto_path_mappings_path = + options[i].second; } else if (options[i].first == "runtime_import_prefix") { // Path to use as a prefix on #imports of runtime provided headers in the // generated files. When integrating ObjC protos into a build system, // this can be used to avoid having to add the runtime directory to the // header search path since the generate #import will be more complete. - generation_options.runtime_import_prefix = StripSuffixString(options[i].second, "/"); + generation_options.runtime_import_prefix = + TProtoStringType(y_absl::StripSuffix(options[i].second, "/")); } else if (options[i].first == "package_to_prefix_mappings_path") { // Path to use for when loading the objc class prefix mappings to use. - // The `objc_class_prefix` file option is always honored first if one is present. - // This option also has precedent over the use_package_as_prefix option. + // The `objc_class_prefix` file option is always honored first if one is + // present. This option also has precedent over the use_package_as_prefix + // option. // // The format of the file is: // - An entry is a line of "package=prefix". @@ -215,7 +230,8 @@ bool ObjectiveCGenerator::GenerateAll( if (StringToBool(options[i].second, &value)) { SetUseProtoPackageAsDefaultPrefix(value); } else { - *error = "error: Unknown use_package_as_prefix: " + options[i].second; + *error = y_absl::StrCat("error: Unknown use_package_as_prefix: ", + options[i].second); return false; } } else if (options[i].first == "proto_package_prefix_exceptions_path") { @@ -230,25 +246,54 @@ bool ObjectiveCGenerator::GenerateAll( // - A comment can go on a line after a expected package/prefix pair. // (i.e. - "some.proto.package # comment") SetProtoPackagePrefixExceptionList(options[i].second); + } else if (options[i].first == "package_as_prefix_forced_prefix") { + // String to use as the prefix when deriving a prefix from the package + // name. So this only applies when use_package_as_prefix is also used. + SetForcedPackagePrefix(options[i].second); } else if (options[i].first == "headers_use_forward_declarations") { if (!StringToBool(options[i].second, &generation_options.headers_use_forward_declarations)) { - *error = "error: Unknown value for headers_use_forward_declarations: " + options[i].second; + *error = y_absl::StrCat( + "error: Unknown value for headers_use_forward_declarations: ", + options[i].second); + return false; + } + } else if (options[i].first == "experimental_multi_source_generation") { + // This is an experimental option, and could be removed or change at any + // time; it is not documented in the README.md for that reason. + // + // Enables a mode where each ObjC class (messages and roots) generates to + // a unique .m file; this is to explore impacts on code size when not + // compiling/linking with `-ObjC` as then only linker visible needs should + // be pulled into the builds. + if (!StringToBool( + options[i].second, + &generation_options.experimental_multi_source_generation)) { + *error = y_absl::StrCat( + "error: Unknown value for experimental_multi_source_generation: ", + options[i].second); return false; } } else { - *error = "error: Unknown generator option: " + options[i].first; + *error = + y_absl::StrCat("error: Unknown generator option: ", options[i].first); return false; } } + // Multi source generation forces off the use of fwd decls in favor of + // imports. + if (generation_options.experimental_multi_source_generation) { + generation_options.headers_use_forward_declarations = false; + } + // ----------------------------------------------------------------- // These are not official generation options and could be removed/changed in // the future and doing that won't count as a breaking change. - bool headers_only = getenv("GPB_OBJC_HEADERS_ONLY") != NULL; - std::unordered_set<TProtoStringType> skip_impls; - if (getenv("GPB_OBJC_SKIP_IMPLS_FILE") != NULL) { + bool headers_only = getenv("GPB_OBJC_HEADERS_ONLY") != nullptr; + y_absl::flat_hash_set<TProtoStringType> skip_impls; + if (getenv("GPB_OBJC_SKIP_IMPLS_FILE") != nullptr) { std::ifstream skip_file(getenv("GPB_OBJC_SKIP_IMPLS_FILE")); if (skip_file.is_open()) { std::string line; @@ -270,27 +315,83 @@ bool ObjectiveCGenerator::GenerateAll( } FileGenerator::CommonState state; - for (int i = 0; i < files.size(); i++) { - const FileDescriptor* file = files[i]; - FileGenerator file_generator(file, generation_options, state); + for (const auto& file : files) { + const FileGenerator file_generator(file, generation_options, state); TProtoStringType filepath = FilePath(file); // Generate header. { - std::unique_ptr<io::ZeroCopyOutputStream> output( - context->Open(filepath + ".pbobjc.h")); - io::Printer printer(output.get(), '$'); + auto output = + y_absl::WrapUnique(context->Open(y_absl::StrCat(filepath, ".pbobjc.h"))); + io::Printer printer(output.get()); file_generator.GenerateHeader(&printer); + if (printer.failed()) { + *error = y_absl::StrCat("error: internal error generating a header: ", + file->name()); + return false; + } } - // Generate m file. + // Generate m file(s). if (!headers_only && skip_impls.count(file->name()) == 0) { - std::unique_ptr<io::ZeroCopyOutputStream> output( - context->Open(filepath + ".pbobjc.m")); - io::Printer printer(output.get(), '$'); - file_generator.GenerateSource(&printer); - } - } + if (generation_options.experimental_multi_source_generation) { + int file_number = 0; + + // Generate the Root and FileDescriptor (if needed). + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(NumberedObjCMFileName(filepath, file_number++))); + io::Printer printer(output.get()); + file_generator.GenerateGlobalSource(&printer); + if (printer.failed()) { + *error = y_absl::StrCat( + "error: internal error generating an implementation:", + file->name()); + return false; + } + } + + // Enums only generate C functions, so they can all go in one file as + // dead stripping anything not used. + if (file_generator.NumEnums() > 0) { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(NumberedObjCMFileName(filepath, file_number++))); + io::Printer printer(output.get()); + file_generator.GenerateSourceForEnums(&printer); + if (printer.failed()) { + *error = y_absl::StrCat( + "error: internal error generating an enum implementation(s):", + file->name()); + return false; + } + } + + for (int i = 0; i < file_generator.NumMessages(); ++i) { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(NumberedObjCMFileName(filepath, file_number++))); + io::Printer printer(output.get()); + file_generator.GenerateSourceForMessage(i, &printer); + if (printer.failed()) { + *error = y_absl::StrCat( + "error: internal error generating an message implementation:", + file->name(), "::", i); + return false; + } + } + } else { + auto output = y_absl::WrapUnique( + context->Open(y_absl::StrCat(filepath, ".pbobjc.m"))); + io::Printer printer(output.get()); + file_generator.GenerateSource(&printer); + if (printer.failed()) { + *error = y_absl::StrCat( + "error: internal error generating an implementation:", + file->name()); + return false; + } + } + } // if (!headers_only && skip_impls.count(file->name()) == 0) + } // for(file : files) return true; } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/generator.h index cdaac67c3b..34767e45a6 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_generator.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/generator.h @@ -34,10 +34,13 @@ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ #include <string> -#include <google/protobuf/compiler/code_generator.h> -#include <google/protobuf/descriptor.h> +#include <vector> -#include <google/protobuf/port_def.inc> +#include "google/protobuf/compiler/code_generator.h" +#include "google/protobuf/descriptor.h" + +// Must be included last +#include "google/protobuf/port_def.inc" namespace google { namespace protobuf { @@ -50,8 +53,8 @@ namespace objectivec { // CodeGenerator with the CommandLineInterface in your main() function. class PROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator { public: - ObjectiveCGenerator(); - ~ObjectiveCGenerator(); + ObjectiveCGenerator() = default; + ~ObjectiveCGenerator() override = default; ObjectiveCGenerator(const ObjectiveCGenerator&) = delete; ObjectiveCGenerator& operator=(const ObjectiveCGenerator&) = delete; @@ -74,6 +77,6 @@ class PROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator { } // namespace protobuf } // namespace google -#include <google/protobuf/port_undef.inc> +#include "google/protobuf/port_undef.inc" #endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/helpers.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/helpers.cc new file mode 100644 index 0000000000..4d90adeb7d --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/helpers.cc @@ -0,0 +1,399 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/helpers.h" + +#include <string> +#include <vector> + +#include "y_absl/log/absl_log.h" +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/escaping.h" +#include "y_absl/strings/match.h" +#include "y_absl/strings/str_replace.h" +#include "y_absl/strings/str_split.h" +#include "y_absl/strings/string_view.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/strtod.h" +#include "google/protobuf/stubs/common.h" +#include <google/protobuf/stubs/port.h> + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +TProtoStringType EscapeTrigraphs(y_absl::string_view to_escape) { + return y_absl::StrReplaceAll(to_escape, {{"?", "\\?"}}); +} + +namespace { + +TProtoStringType GetZeroEnumNameForFlagType(const FlagType flag_type) { + switch (flag_type) { + case FLAGTYPE_DESCRIPTOR_INITIALIZATION: + return "GPBDescriptorInitializationFlag_None"; + case FLAGTYPE_EXTENSION: + return "GPBExtensionNone"; + case FLAGTYPE_FIELD: + return "GPBFieldNone"; + default: + Y_ABSL_LOG(FATAL) << "Can't get here."; + return "0"; + } +} + +TProtoStringType GetEnumNameForFlagType(const FlagType flag_type) { + switch (flag_type) { + case FLAGTYPE_DESCRIPTOR_INITIALIZATION: + return "GPBDescriptorInitializationFlags"; + case FLAGTYPE_EXTENSION: + return "GPBExtensionOptions"; + case FLAGTYPE_FIELD: + return "GPBFieldFlags"; + default: + Y_ABSL_LOG(FATAL) << "Can't get here."; + return TProtoStringType(); + } +} + +TProtoStringType HandleExtremeFloatingPoint(TProtoStringType val, bool add_float_suffix) { + if (val == "nan") { + return "NAN"; + } else if (val == "inf") { + return "INFINITY"; + } else if (val == "-inf") { + return "-INFINITY"; + } else { + // float strings with ., e or E need to have f appended + if (add_float_suffix && + (y_absl::StrContains(val, '.') || y_absl::StrContains(val, 'e') || + y_absl::StrContains(val, 'E'))) { + return y_absl::StrCat(val, "f"); + } + return val; + } +} + +} // namespace + +TProtoStringType GetCapitalizedType(const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: + return "Int32"; + case FieldDescriptor::TYPE_UINT32: + return "UInt32"; + case FieldDescriptor::TYPE_SINT32: + return "SInt32"; + case FieldDescriptor::TYPE_FIXED32: + return "Fixed32"; + case FieldDescriptor::TYPE_SFIXED32: + return "SFixed32"; + case FieldDescriptor::TYPE_INT64: + return "Int64"; + case FieldDescriptor::TYPE_UINT64: + return "UInt64"; + case FieldDescriptor::TYPE_SINT64: + return "SInt64"; + case FieldDescriptor::TYPE_FIXED64: + return "Fixed64"; + case FieldDescriptor::TYPE_SFIXED64: + return "SFixed64"; + case FieldDescriptor::TYPE_FLOAT: + return "Float"; + case FieldDescriptor::TYPE_DOUBLE: + return "Double"; + case FieldDescriptor::TYPE_BOOL: + return "Bool"; + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Bytes"; + case FieldDescriptor::TYPE_ENUM: + return "Enum"; + case FieldDescriptor::TYPE_GROUP: + return "Group"; + case FieldDescriptor::TYPE_MESSAGE: + return "Message"; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + Y_ABSL_LOG(FATAL) << "Can't get here."; + return TProtoStringType(); +} + +ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) { + switch (field_type) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SFIXED32: + return OBJECTIVECTYPE_INT32; + + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_FIXED32: + return OBJECTIVECTYPE_UINT32; + + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_SFIXED64: + return OBJECTIVECTYPE_INT64; + + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_FIXED64: + return OBJECTIVECTYPE_UINT64; + + case FieldDescriptor::TYPE_FLOAT: + return OBJECTIVECTYPE_FLOAT; + + case FieldDescriptor::TYPE_DOUBLE: + return OBJECTIVECTYPE_DOUBLE; + + case FieldDescriptor::TYPE_BOOL: + return OBJECTIVECTYPE_BOOLEAN; + + case FieldDescriptor::TYPE_STRING: + return OBJECTIVECTYPE_STRING; + + case FieldDescriptor::TYPE_BYTES: + return OBJECTIVECTYPE_DATA; + + case FieldDescriptor::TYPE_ENUM: + return OBJECTIVECTYPE_ENUM; + + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + return OBJECTIVECTYPE_MESSAGE; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + Y_ABSL_LOG(FATAL) << "Can't get here."; + return OBJECTIVECTYPE_INT32; +} + +TProtoStringType GPBGenericValueFieldName(const FieldDescriptor* field) { + // Returns the field within the GPBGenericValue union to use for the given + // field. + if (field->is_repeated()) { + return "valueMessage"; + } + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return "valueInt32"; + case FieldDescriptor::CPPTYPE_UINT32: + return "valueUInt32"; + case FieldDescriptor::CPPTYPE_INT64: + return "valueInt64"; + case FieldDescriptor::CPPTYPE_UINT64: + return "valueUInt64"; + case FieldDescriptor::CPPTYPE_FLOAT: + return "valueFloat"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return "valueDouble"; + case FieldDescriptor::CPPTYPE_BOOL: + return "valueBool"; + case FieldDescriptor::CPPTYPE_STRING: + if (field->type() == FieldDescriptor::TYPE_BYTES) { + return "valueData"; + } else { + return "valueString"; + } + case FieldDescriptor::CPPTYPE_ENUM: + return "valueEnum"; + case FieldDescriptor::CPPTYPE_MESSAGE: + return "valueMessage"; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + Y_ABSL_LOG(FATAL) << "Can't get here."; + return TProtoStringType(); +} + +TProtoStringType DefaultValue(const FieldDescriptor* field) { + // Repeated fields don't have defaults. + if (field->is_repeated()) { + return "nil"; + } + + // Switch on cpp_type since we need to know which default_value_* method + // of FieldDescriptor to call. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + // gcc and llvm reject the decimal form of kint32min and kint64min. + if (field->default_value_int32() == INT_MIN) { + return "-0x80000000"; + } + return y_absl::StrCat(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return y_absl::StrCat(field->default_value_uint32(), "U"); + case FieldDescriptor::CPPTYPE_INT64: + // gcc and llvm reject the decimal form of kint32min and kint64min. + if (field->default_value_int64() == LLONG_MIN) { + return "-0x8000000000000000LL"; + } + return y_absl::StrCat(field->default_value_int64(), "LL"); + case FieldDescriptor::CPPTYPE_UINT64: + return y_absl::StrCat(field->default_value_uint64(), "ULL"); + case FieldDescriptor::CPPTYPE_DOUBLE: + return HandleExtremeFloatingPoint( + io::SimpleDtoa(field->default_value_double()), false); + case FieldDescriptor::CPPTYPE_FLOAT: + return HandleExtremeFloatingPoint( + io::SimpleFtoa(field->default_value_float()), true); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "YES" : "NO"; + case FieldDescriptor::CPPTYPE_STRING: { + const bool has_default_value = field->has_default_value(); + y_absl::string_view default_string = field->default_value_string(); + if (!has_default_value || default_string.length() == 0) { + // If the field is defined as being the empty string, + // then we will just assign to nil, as the empty string is the + // default for both strings and data. + return "nil"; + } + if (field->type() == FieldDescriptor::TYPE_BYTES) { + // We want constant fields in our data structures so we can + // declare them as static. To achieve this we cheat and stuff + // a escaped c string (prefixed with a length) into the data + // field, and cast it to an (NSData*) so it will compile. + // The runtime library knows how to handle it. + + // Must convert to a standard byte order for packing length into + // a cstring. + arc_ui32 length = ghtonl(default_string.length()); + TProtoStringType bytes((const char*)&length, sizeof(length)); + y_absl::StrAppend(&bytes, default_string); + return y_absl::StrCat("(NSData*)\"", + EscapeTrigraphs(y_absl::CEscape(bytes)), "\""); + } else { + return y_absl::StrCat( + "@\"", EscapeTrigraphs(y_absl::CEscape(default_string)), "\""); + } + } + case FieldDescriptor::CPPTYPE_ENUM: + return EnumValueName(field->default_value_enum()); + case FieldDescriptor::CPPTYPE_MESSAGE: + return "nil"; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + Y_ABSL_LOG(FATAL) << "Can't get here."; + return TProtoStringType(); +} + +TProtoStringType BuildFlagsString(FlagType flag_type, + const std::vector<TProtoStringType>& strings) { + if (strings.empty()) { + return GetZeroEnumNameForFlagType(flag_type); + } else if (strings.size() == 1) { + return strings[0]; + } + TProtoStringType string = + y_absl::StrCat("(", GetEnumNameForFlagType(flag_type), ")("); + for (size_t i = 0; i != strings.size(); ++i) { + if (i > 0) { + string.append(" | "); + } + string.append(strings[i]); + } + string.append(")"); + return string; +} + +TProtoStringType ObjCClass(y_absl::string_view class_name) { + return y_absl::StrCat("GPBObjCClass(", class_name, ")"); +} + +TProtoStringType ObjCClassDeclaration(y_absl::string_view class_name) { + return y_absl::StrCat("GPBObjCClassDeclaration(", class_name, ");"); +} + +TProtoStringType BuildCommentsString(const SourceLocation& location, + bool prefer_single_line) { + y_absl::string_view comments = location.leading_comments.empty() + ? location.trailing_comments + : location.leading_comments; + std::vector<y_absl::string_view> lines; + lines = y_absl::StrSplit(comments, '\n', y_absl::AllowEmpty()); + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + // If there are no comments, just return an empty string. + if (lines.empty()) { + return ""; + } + + TProtoStringType prefix; + TProtoStringType suffix; + TProtoStringType final_comments; + TProtoStringType epilogue; + + bool add_leading_space = false; + + if (prefer_single_line && lines.size() == 1) { + prefix = "/** "; + suffix = " */\n"; + } else { + prefix = "* "; + suffix = "\n"; + y_absl::StrAppend(&final_comments, "/**\n"); + epilogue = " **/\n"; + add_leading_space = true; + } + + for (size_t i = 0; i < lines.size(); i++) { + TProtoStringType line = y_absl::StrReplaceAll( + y_absl::StripPrefix(lines[i], " "), + {// HeaderDoc and appledoc use '\' and '@' for markers; escape them. + {"\\", "\\\\"}, + {"@", "\\@"}, + // Decouple / from * to not have inline comments inside comments. + {"/*", "/\\*"}, + {"*/", "*\\/"}}); + line = prefix + line; + y_absl::StripAsciiWhitespace(&line); + // If not a one line, need to add the first space before *, as + // y_absl::StripAsciiWhitespace would have removed it. + line = y_absl::StrCat(add_leading_space ? " " : "", line); + y_absl::StrAppend(&final_comments, line, suffix); + } + return y_absl::StrCat(final_comments, epilogue); +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/helpers.h new file mode 100644 index 0000000000..73f67e13d7 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/helpers.h @@ -0,0 +1,155 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Helper functions for generating ObjectiveC code. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ + +#include <string> +#include <vector> + +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// Escape C++ trigraphs by escaping question marks to "\?". +TProtoStringType EscapeTrigraphs(y_absl::string_view to_escape); + +enum ObjectiveCType { + OBJECTIVECTYPE_INT32, + OBJECTIVECTYPE_UINT32, + OBJECTIVECTYPE_INT64, + OBJECTIVECTYPE_UINT64, + OBJECTIVECTYPE_FLOAT, + OBJECTIVECTYPE_DOUBLE, + OBJECTIVECTYPE_BOOLEAN, + OBJECTIVECTYPE_STRING, + OBJECTIVECTYPE_DATA, + OBJECTIVECTYPE_ENUM, + OBJECTIVECTYPE_MESSAGE +}; + +enum FlagType { + FLAGTYPE_DESCRIPTOR_INITIALIZATION, + FLAGTYPE_EXTENSION, + FLAGTYPE_FIELD +}; + +TProtoStringType GetCapitalizedType(const FieldDescriptor* field); + +ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type); + +inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) { + return GetObjectiveCType(field->type()); +} + +inline bool IsPrimitiveType(const FieldDescriptor* field) { + ObjectiveCType type = GetObjectiveCType(field); + switch (type) { + case OBJECTIVECTYPE_INT32: + case OBJECTIVECTYPE_UINT32: + case OBJECTIVECTYPE_INT64: + case OBJECTIVECTYPE_UINT64: + case OBJECTIVECTYPE_FLOAT: + case OBJECTIVECTYPE_DOUBLE: + case OBJECTIVECTYPE_BOOLEAN: + case OBJECTIVECTYPE_ENUM: + return true; + break; + default: + return false; + } +} + +inline bool IsReferenceType(const FieldDescriptor* field) { + return !IsPrimitiveType(field); +} + +TProtoStringType GPBGenericValueFieldName(const FieldDescriptor* field); +TProtoStringType DefaultValue(const FieldDescriptor* field); + +TProtoStringType BuildFlagsString(FlagType type, + const std::vector<TProtoStringType>& strings); + +// Returns a symbol that can be used in C code to refer to an Objective-C +// class without initializing the class. +TProtoStringType ObjCClass(y_absl::string_view class_name); + +// Declares an Objective-C class without initializing the class so that it can +// be refrerred to by ObjCClass. +TProtoStringType ObjCClassDeclaration(y_absl::string_view class_name); + +// Builds HeaderDoc/appledoc style comments out of the comments in the .proto +// file. +TProtoStringType BuildCommentsString(const SourceLocation& location, + bool prefer_single_line); + +template <class TDescriptor> +TProtoStringType GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, + const FileDescriptor* file = nullptr, + bool preSpace = true, + bool postNewline = false) { + bool isDeprecated = descriptor->options().deprecated(); + // The file is only passed when checking Messages & Enums, so those types + // get tagged. At the moment, it doesn't seem to make sense to tag every + // field or enum value with when the file is deprecated. + bool isFileLevelDeprecation = false; + if (!isDeprecated && file) { + isFileLevelDeprecation = file->options().deprecated(); + isDeprecated = isFileLevelDeprecation; + } + if (isDeprecated) { + TProtoStringType message; + const FileDescriptor* sourceFile = descriptor->file(); + if (isFileLevelDeprecation) { + message = y_absl::StrCat(sourceFile->name(), " is deprecated."); + } else { + message = y_absl::StrCat(descriptor->full_name(), " is deprecated (see ", + sourceFile->name(), ")."); + } + + return y_absl::StrCat(preSpace ? " " : "", "GPB_DEPRECATED_MSG(\"", message, + "\")", postNewline ? "\n" : ""); + } else { + return ""; + } +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/import_writer.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/import_writer.cc new file mode 100644 index 0000000000..de6f6ab66c --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/import_writer.cc @@ -0,0 +1,255 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/import_writer.h" + +#include <iostream> +#include <ostream> +#include <string> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/match.h" +#include "google/protobuf/compiler/objectivec/line_consumer.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/printer.h" + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +class ProtoFrameworkCollector : public LineConsumer { + public: + explicit ProtoFrameworkCollector( + y_absl::flat_hash_map<TProtoStringType, TProtoStringType>* + inout_proto_file_to_framework_name) + : map_(inout_proto_file_to_framework_name) {} + + bool ConsumeLine(y_absl::string_view line, TProtoStringType* out_error) override; + + private: + y_absl::flat_hash_map<TProtoStringType, TProtoStringType>* map_; +}; + +bool ProtoFrameworkCollector::ConsumeLine(y_absl::string_view line, + TProtoStringType* out_error) { + int offset = line.find(':'); + if (offset == y_absl::string_view::npos) { + *out_error = y_absl::StrCat( + "Framework/proto file mapping line without colon sign: '", line, "'."); + return false; + } + y_absl::string_view framework_name = + y_absl::StripAsciiWhitespace(line.substr(0, offset)); + y_absl::string_view proto_file_list = + y_absl::StripAsciiWhitespace(line.substr(offset + 1)); + + int start = 0; + while (start < proto_file_list.length()) { + offset = proto_file_list.find(',', start); + if (offset == y_absl::string_view::npos) { + offset = proto_file_list.length(); + } + + y_absl::string_view proto_file = y_absl::StripAsciiWhitespace( + proto_file_list.substr(start, offset - start)); + if (!proto_file.empty()) { + auto existing_entry = map_->find(proto_file); + if (existing_entry != map_->end()) { + std::cerr << "warning: duplicate proto file reference, replacing " + "framework entry for '" + << proto_file << "' with '" << framework_name << "' (was '" + << existing_entry->second << "')." << std::endl; + std::cerr.flush(); + } + + if (y_absl::StrContains(proto_file, ' ')) { + std::cerr << "note: framework mapping file had a proto file with a " + "space in, hopefully that isn't a missing comma: '" + << proto_file << "'" << std::endl; + std::cerr.flush(); + } + + (*map_)[proto_file] = TProtoStringType(framework_name); + } + + start = offset + 1; + } + + return true; +} + +} // namespace + +ImportWriter::ImportWriter( + const TProtoStringType& generate_for_named_framework, + const TProtoStringType& named_framework_to_proto_path_mappings_path, + const TProtoStringType& runtime_import_prefix, bool for_bundled_proto) + : generate_for_named_framework_(generate_for_named_framework), + named_framework_to_proto_path_mappings_path_( + named_framework_to_proto_path_mappings_path), + runtime_import_prefix_(runtime_import_prefix), + for_bundled_proto_(for_bundled_proto), + need_to_parse_mapping_file_(true) {} + +void ImportWriter::AddFile(const FileDescriptor* file, + const TProtoStringType& header_extension) { + if (IsProtobufLibraryBundledProtoFile(file)) { + // The imports of the WKTs are only needed within the library itself, + // in other cases, they get skipped because the generated code already + // import GPBProtocolBuffers.h and hence proves them. + if (for_bundled_proto_) { + protobuf_imports_.emplace_back( + y_absl::StrCat("GPB", FilePathBasename(file), header_extension)); + } + return; + } + + // Lazy parse any mappings. + if (need_to_parse_mapping_file_) { + ParseFrameworkMappings(); + } + + auto proto_lookup = proto_file_to_framework_name_.find(file->name()); + if (proto_lookup != proto_file_to_framework_name_.end()) { + other_framework_imports_.emplace_back(y_absl::StrCat( + proto_lookup->second, "/", FilePathBasename(file), header_extension)); + return; + } + + if (!generate_for_named_framework_.empty()) { + other_framework_imports_.push_back( + y_absl::StrCat(generate_for_named_framework_, "/", FilePathBasename(file), + header_extension)); + return; + } + + other_imports_.push_back(FilePath(file) + header_extension); +} + +void ImportWriter::AddRuntimeImport(const TProtoStringType& header_name) { + protobuf_imports_.push_back(header_name); +} + +void ImportWriter::PrintFileImports(io::Printer* p) const { + if (!other_framework_imports_.empty()) { + for (const auto& header : other_framework_imports_) { + p->Print("#import <$header$>\n", "header", header); + } + } + + if (!other_imports_.empty()) { + if (!other_framework_imports_.empty()) { + p->Print("\n"); + } + + for (const auto& header : other_imports_) { + p->Print("#import \"$header$\"\n", "header", header); + } + } +} + +void ImportWriter::PrintRuntimeImports(io::Printer* p, + bool default_cpp_symbol) const { + // Given an override, use that. + if (!runtime_import_prefix_.empty()) { + for (const auto& header : protobuf_imports_) { + p->Print("#import \"$import_prefix$/$header$\"\n", "header", header, + "import_prefix", runtime_import_prefix_); + } + return; + } + + // If bundled, no need to do the framework support below. + if (for_bundled_proto_) { + Y_ABSL_DCHECK(!default_cpp_symbol); + for (const auto& header : protobuf_imports_) { + p->Print("#import \"$header$\"\n", "header", header); + } + return; + } + + const TProtoStringType cpp_symbol( + ProtobufFrameworkImportSymbol(ProtobufLibraryFrameworkName)); + + if (default_cpp_symbol) { + p->Print( + // clang-format off + "// This CPP symbol can be defined to use imports that match up to the framework\n" + "// imports needed when using CocoaPods.\n" + "#if !defined($cpp_symbol$)\n" + " #define $cpp_symbol$ 0\n" + "#endif\n" + "\n", + // clang-format on + "cpp_symbol", cpp_symbol); + } + + p->Print("#if $cpp_symbol$\n", "cpp_symbol", cpp_symbol); + for (const auto& header : protobuf_imports_) { + p->Print(" #import <$framework_name$/$header$>\n", "framework_name", + ProtobufLibraryFrameworkName, "header", header); + } + p->Print("#else\n"); + for (const auto& header : protobuf_imports_) { + p->Print(" #import \"$header$\"\n", "header", header); + } + p->Print("#endif\n"); +} + +void ImportWriter::ParseFrameworkMappings() { + need_to_parse_mapping_file_ = false; + if (named_framework_to_proto_path_mappings_path_.empty()) { + return; // Nothing to do. + } + + ProtoFrameworkCollector collector(&proto_file_to_framework_name_); + TProtoStringType parse_error; + if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_, &collector, + &parse_error)) { + std::cerr << "error parsing " + << named_framework_to_proto_path_mappings_path_ << " : " + << parse_error << std::endl; + std::cerr.flush(); + } +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/import_writer.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/import_writer.h new file mode 100644 index 0000000000..d4ed37d3a8 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/import_writer.h @@ -0,0 +1,82 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_IMPORT_WRITER_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_IMPORT_WRITER_H__ + +#include <string> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// Helper class for parsing framework import mappings and generating +// import statements. +class ImportWriter { + public: + ImportWriter(const TProtoStringType& generate_for_named_framework, + const TProtoStringType& named_framework_to_proto_path_mappings_path, + const TProtoStringType& runtime_import_prefix, + bool for_bundled_proto); + ~ImportWriter() = default; + + void AddFile(const FileDescriptor* file, const TProtoStringType& header_extension); + void AddRuntimeImport(const TProtoStringType& header_name); + + void PrintFileImports(io::Printer* p) const; + void PrintRuntimeImports(io::Printer* p, bool default_cpp_symbol) const; + + private: + void ParseFrameworkMappings(); + + const TProtoStringType generate_for_named_framework_; + const TProtoStringType named_framework_to_proto_path_mappings_path_; + const TProtoStringType runtime_import_prefix_; + y_absl::flat_hash_map<TProtoStringType, TProtoStringType> proto_file_to_framework_name_; + bool for_bundled_proto_; + bool need_to_parse_mapping_file_; + + std::vector<TProtoStringType> protobuf_imports_; + std::vector<TProtoStringType> other_framework_imports_; + std::vector<TProtoStringType> other_imports_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_IMPORT_WRITER_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/line_consumer.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/line_consumer.cc new file mode 100644 index 0000000000..f47be8186e --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/line_consumer.cc @@ -0,0 +1,212 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef _MSC_VER +#include <unistd.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> + +#include <climits> +#include <fstream> +#include <iostream> +#include <sstream> +#include <string> +#include <vector> + +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/objectivec/line_consumer.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" + +#ifdef _WIN32 +#include "google/protobuf/io/io_win32.h" +#endif + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// <io.h> is transitively included in this file. Import the functions explicitly +// in this port namespace to avoid ambiguous definition. +namespace posix { +#ifdef _WIN32 +using google::protobuf::io::win32::open; +#else // !_WIN32 +using ::open; +#endif // _WIN32 +} // namespace posix + +namespace { + +bool ascii_isnewline(char c) { return c == '\n' || c == '\r'; } + +bool ReadLine(y_absl::string_view* input, y_absl::string_view* line) { + for (int len = 0; len < input->size(); ++len) { + if (ascii_isnewline((*input)[len])) { + *line = y_absl::string_view(input->data(), len); + ++len; // advance over the newline + *input = y_absl::string_view(input->data() + len, input->size() - len); + return true; + } + } + return false; // Ran out of input with no newline. +} + +void RemoveComment(y_absl::string_view* input) { + int offset = input->find('#'); + if (offset != y_absl::string_view::npos) { + input->remove_suffix(input->length() - offset); + } +} + +class Parser { + public: + explicit Parser(LineConsumer* line_consumer) + : line_consumer_(line_consumer), line_(0) {} + + // Feeds in some input, parse what it can, returning success/failure. Calling + // again after an error is undefined. + bool ParseChunk(y_absl::string_view chunk, TProtoStringType* out_error); + + // Should be called to finish parsing (after all input has been provided via + // successful calls to ParseChunk(), calling after a ParseChunk() failure is + // undefined). Returns success/failure. + bool Finish(TProtoStringType* out_error); + + int last_line() const { return line_; } + + private: + LineConsumer* line_consumer_; + int line_; + TProtoStringType leftover_; +}; + +bool Parser::ParseChunk(y_absl::string_view chunk, TProtoStringType* out_error) { + y_absl::string_view full_chunk; + if (!leftover_.empty()) { + leftover_ += TProtoStringType(chunk); + full_chunk = y_absl::string_view(leftover_); + } else { + full_chunk = chunk; + } + + y_absl::string_view line; + while (ReadLine(&full_chunk, &line)) { + ++line_; + RemoveComment(&line); + line = y_absl::StripAsciiWhitespace(line); + if (!line.empty() && !line_consumer_->ConsumeLine(line, out_error)) { + if (out_error->empty()) { + *out_error = "ConsumeLine failed without setting an error."; + } + leftover_.clear(); + return false; + } + } + + if (full_chunk.empty()) { + leftover_.clear(); + } else { + leftover_ = TProtoStringType(full_chunk); + } + return true; +} + +bool Parser::Finish(TProtoStringType* out_error) { + // If there is still something to go, flush it with a newline. + if (!leftover_.empty() && !ParseChunk("\n", out_error)) { + return false; + } + // This really should never fail if ParseChunk succeeded, but check to be + // sure. + if (!leftover_.empty()) { + *out_error = "ParseSimple Internal error: finished with pending data."; + return false; + } + return true; +} + +} // namespace + +bool ParseSimpleFile(y_absl::string_view path, LineConsumer* line_consumer, + TProtoStringType* out_error) { + int fd; + do { + fd = posix::open(TProtoStringType(path).c_str(), O_RDONLY); + } while (fd < 0 && errno == EINTR); + if (fd < 0) { + *out_error = + y_absl::StrCat("error: Unable to open \"", path, "\", ", strerror(errno)); + return false; + } + io::FileInputStream file_stream(fd); + file_stream.SetCloseOnDelete(true); + + return ParseSimpleStream(file_stream, path, line_consumer, out_error); +} + +bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream, + y_absl::string_view stream_name, + LineConsumer* line_consumer, TProtoStringType* out_error) { + TProtoStringType local_error; + Parser parser(line_consumer); + const void* buf; + int buf_len; + while (input_stream.Next(&buf, &buf_len)) { + if (buf_len == 0) { + continue; + } + + if (!parser.ParseChunk( + y_absl::string_view(static_cast<const char*>(buf), buf_len), + &local_error)) { + *out_error = y_absl::StrCat("error: ", stream_name, " Line ", + parser.last_line(), ", ", local_error); + return false; + } + } + if (!parser.Finish(&local_error)) { + *out_error = y_absl::StrCat("error: ", stream_name, " Line ", + parser.last_line(), ", ", local_error); + return false; + } + return true; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/line_consumer.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/line_consumer.h new file mode 100644 index 0000000000..668fdb1d12 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/line_consumer.h @@ -0,0 +1,74 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_LINE_CONSUMER_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_LINE_CONSUMER_H__ + +#include <string> +#include <vector> + +#include "google/protobuf/io/zero_copy_stream.h" + +// Must be included last +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// TODO(b/250947994): PROTOC_EXPORT is only used to allow the CMake build to +// find/link these in the unittest, this is not public api. + +// Helper for parsing simple files. +class PROTOC_EXPORT LineConsumer { + public: + LineConsumer() = default; + virtual ~LineConsumer() = default; + virtual bool ConsumeLine(y_absl::string_view line, TProtoStringType* out_error) = 0; +}; + +bool PROTOC_EXPORT ParseSimpleFile(y_absl::string_view path, + LineConsumer* line_consumer, + TProtoStringType* out_error); + +bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream, + y_absl::string_view stream_name, + LineConsumer* line_consumer, + TProtoStringType* out_error); + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_LINE_CONSUMER_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/map_field.cc index 933f0ce73d..96b777027c 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/map_field.cc @@ -28,12 +28,16 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <map> +#include "google/protobuf/compiler/objectivec/map_field.h" + #include <string> +#include <vector> -#include <google/protobuf/compiler/objectivec/objectivec_map_field.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/io/printer.h> +#include "y_absl/container/btree_set.h" +#include "y_absl/log/absl_log.h" +#include "y_absl/strings/match.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" namespace google { namespace protobuf { @@ -75,16 +79,15 @@ const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) { // Some compilers report reaching end of function even though all cases of // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; + Y_ABSL_LOG(FATAL) << "Can't get here."; + return nullptr; } } // namespace MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) : RepeatedFieldGenerator(descriptor) { - const FieldDescriptor* key_descriptor = - descriptor->message_type()->map_key(); + const FieldDescriptor* key_descriptor = descriptor->message_type()->map_key(); const FieldDescriptor* value_descriptor = descriptor->message_type()->map_value(); value_field_generator_.reset(FieldGenerator::Make(value_descriptor)); @@ -96,21 +99,24 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) // Build custom field flags. std::vector<TProtoStringType> field_flags; - field_flags.push_back("GPBFieldMapKey" + GetCapitalizedType(key_descriptor)); + field_flags.push_back( + y_absl::StrCat("GPBFieldMapKey", GetCapitalizedType(key_descriptor))); // Pull over the current text format custom name values that was calculated. - if (variables_["fieldflags"].find("GPBFieldTextFormatNameCustom") != - TProtoStringType::npos) { + if (y_absl::StrContains(variables_["fieldflags"], + "GPBFieldTextFormatNameCustom")) { field_flags.push_back("GPBFieldTextFormatNameCustom"); } // Pull over some info from the value's flags. const TProtoStringType& value_field_flags = value_field_generator_->variable("fieldflags"); - if (value_field_flags.find("GPBFieldHasDefaultValue") != TProtoStringType::npos) { + if (y_absl::StrContains(value_field_flags, "GPBFieldHasDefaultValue")) { field_flags.push_back("GPBFieldHasDefaultValue"); } - if (value_field_flags.find("GPBFieldHasEnumDescriptor") != - TProtoStringType::npos) { + if (y_absl::StrContains(value_field_flags, "GPBFieldHasEnumDescriptor")) { field_flags.push_back("GPBFieldHasEnumDescriptor"); + if (y_absl::StrContains(value_field_flags, "GPBFieldClosedEnum")) { + field_flags.push_back("GPBFieldClosedEnum"); + } } variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags); @@ -124,18 +130,17 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) value_is_object_type) { variables_["array_storage_type"] = "NSMutableDictionary"; variables_["array_property_type"] = - "NSMutableDictionary<NSString*, " + - value_field_generator_->variable("storage_type") + "*>"; + y_absl::StrCat("NSMutableDictionary<NSString*, ", + value_field_generator_->variable("storage_type"), "*>"); } else { - TProtoStringType class_name("GPB"); - class_name += MapEntryTypeName(key_descriptor, true); - class_name += MapEntryTypeName(value_descriptor, false); - class_name += "Dictionary"; + TProtoStringType class_name = + y_absl::StrCat("GPB", MapEntryTypeName(key_descriptor, true), + MapEntryTypeName(value_descriptor, false), "Dictionary"); variables_["array_storage_type"] = class_name; if (value_is_object_type) { variables_["array_property_type"] = - class_name + "<" + - value_field_generator_->variable("storage_type") + "*>"; + y_absl::StrCat(class_name, "<", + value_field_generator_->variable("storage_type"), "*>"); } } @@ -145,48 +150,57 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) value_field_generator_->variable("dataTypeSpecific_value"); } -MapFieldGenerator::~MapFieldGenerator() {} - -void MapFieldGenerator::FinishInitialization(void) { +void MapFieldGenerator::FinishInitialization() { RepeatedFieldGenerator::FinishInitialization(); // Use the array_comment support in RepeatedFieldGenerator to output what the // values in the map are. const FieldDescriptor* value_descriptor = descriptor_->message_type()->map_value(); if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) { + TProtoStringType name = variables_["name"]; variables_["array_comment"] = - "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n"; + y_absl::StrCat("// |", name, "| values are |", + value_field_generator_->variable("storage_type"), "|\n"); } } void MapFieldGenerator::DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, + y_absl::btree_set<TProtoStringType>* fwd_decls, bool include_external_types) const { - RepeatedFieldGenerator::DetermineForwardDeclarations( - fwd_decls, include_external_types); + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls, + include_external_types); const FieldDescriptor* value_descriptor = descriptor_->message_type()->map_value(); + // NOTE: Maps with values of enums don't have to worry about adding the + // forward declaration because `GPB*EnumDictionary` isn't generic to the + // specific enum (like say `NSDictionary<String, MyMessage>`) and thus doesn't + // reference the type in the header. + if (GetObjectiveCType(value_descriptor) != OBJECTIVECTYPE_MESSAGE) { + return; + } + + const Descriptor* value_msg_descriptor = value_descriptor->message_type(); + // Within a file there is no requirement on the order of the messages, so // local references need a forward declaration. External files (not WKTs), // need one when requested. - if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE && - ((include_external_types && - !IsProtobufLibraryBundledProtoFile(value_descriptor->file())) || - descriptor_->file() == value_descriptor->file())) { + if ((include_external_types && + !IsProtobufLibraryBundledProtoFile(value_msg_descriptor->file())) || + descriptor_->file() == value_msg_descriptor->file()) { const TProtoStringType& value_storage_type = value_field_generator_->variable("storage_type"); - fwd_decls->insert("@class " + value_storage_type); + fwd_decls->insert(y_absl::StrCat("@class ", value_storage_type, ";")); } } void MapFieldGenerator::DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) const { + y_absl::btree_set<TProtoStringType>* fwd_decls) const { // Class name is already in "storage_type". const FieldDescriptor* value_descriptor = descriptor_->message_type()->map_value(); if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) { - fwd_decls->insert(ObjCClassDeclaration( - value_field_generator_->variable("storage_type"))); + fwd_decls->insert( + ObjCClassDeclaration(value_field_generator_->variable("storage_type"))); } } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/map_field.h index a75aa961d8..d3ceb070d3 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_map_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/map_field.h @@ -31,9 +31,11 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__ -#include <map> +#include <memory> #include <string> -#include <google/protobuf/compiler/objectivec/objectivec_field.h> + +#include "y_absl/container/btree_set.h" +#include "google/protobuf/compiler/objectivec/field.h" namespace google { namespace protobuf { @@ -44,20 +46,19 @@ class MapFieldGenerator : public RepeatedFieldGenerator { friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); public: - virtual void FinishInitialization(void) override; + void FinishInitialization() override; MapFieldGenerator(const MapFieldGenerator&) = delete; MapFieldGenerator& operator=(const MapFieldGenerator&) = delete; protected: explicit MapFieldGenerator(const FieldDescriptor* descriptor); - virtual ~MapFieldGenerator(); + ~MapFieldGenerator() override = default; - virtual void DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) const override; - virtual void DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, - bool include_external_types) const override; + void DetermineObjectiveCClassDefinitions( + y_absl::btree_set<TProtoStringType>* fwd_decls) const override; + void DetermineForwardDeclarations(y_absl::btree_set<TProtoStringType>* fwd_decls, + bool include_external_types) const override; private: std::unique_ptr<FieldGenerator> value_field_generator_; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message.cc new file mode 100644 index 0000000000..089314d361 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message.cc @@ -0,0 +1,631 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/message.h" + +#include <algorithm> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_log.h" +#include "y_absl/strings/escaping.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/objectivec/extension.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/oneof.h" +#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +bool IsMapEntryMessage(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { + // The first item in the object structure is our uint32[] for has bits. + // We then want to order things to make the instances as small as + // possible. So we follow the has bits with: + // 1. Anything always 4 bytes - float, *32, enums + // 2. Anything that is always a pointer (they will be 8 bytes on 64 bit + // builds and 4 bytes on 32bit builds. + // 3. Anything always 8 bytes - double, *64 + // + // NOTE: Bools aren't listed, they were stored in the has bits. + // + // Why? Using 64bit builds as an example, this means worse case, we have + // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes + // are wasted before the 4 byte values. Then if we have an odd number of + // those 4 byte values, the 8 byte values will be pushed down by 32bits to + // keep them aligned. But the structure will end 8 byte aligned, so no + // waste on the end. If you did the reverse order, you could waste 4 bytes + // before the first 8 byte value (after the has array), then a single + // bool on the end would need 7 bytes of padding to make the overall + // structure 8 byte aligned; so 11 bytes, wasted total. + + // Anything repeated is a GPB*Array/NSArray, so pointer. + if (descriptor->is_repeated()) { + return 3; + } + + switch (descriptor->type()) { + // All always 8 bytes. + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_FIXED64: + return 4; + + // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes + // depending on the build architecture. + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + return 3; + + // All always 4 bytes (enums are int32s). + case FieldDescriptor::TYPE_FLOAT: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_ENUM: + return 2; + + // 0 bytes. Stored in the has bits. + case FieldDescriptor::TYPE_BOOL: + return 99; // End of the list (doesn't really matter). + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + Y_ABSL_LOG(FATAL) << "Can't get here."; + return 0; +} + +struct FieldOrderingByStorageSize { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + // Order by grouping. + const int order_group_a = OrderGroupForFieldDescriptor(a); + const int order_group_b = OrderGroupForFieldDescriptor(b); + if (order_group_a != order_group_b) { + return order_group_a < order_group_b; + } + // Within the group, order by field number (provides stable ordering). + return a->number() < b->number(); + } +}; + +struct ExtensionRangeOrdering { + bool operator()(const Descriptor::ExtensionRange* a, + const Descriptor::ExtensionRange* b) const { + return a->start < b->start; + } +}; + +// This is a reduced case of Descriptor::ExtensionRange with just start and end. +struct SimpleExtensionRange { + SimpleExtensionRange(int start, int end) : start(start), end(end){}; + int start; // inclusive + int end; // exclusive + + // Descriptors expose extension ranges in the order they were defined in the + // file, but this reorders and merges the ranges that are contiguous (i.e. - + // [(21,30),(10,20)] -> [(10,30)]) + static std::vector<SimpleExtensionRange> Normalize( + const Descriptor* descriptor) { + std::vector<const Descriptor::ExtensionRange*> sorted_extensions; + sorted_extensions.reserve(descriptor->extension_range_count()); + for (int i = 0; i < descriptor->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor->extension_range(i)); + } + + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeOrdering()); + + std::vector<SimpleExtensionRange> result; + result.reserve(sorted_extensions.size()); + for (const auto ext : sorted_extensions) { + if (!result.empty() && result.back().end == ext->start) { + result.back().end = ext->end; + } else { + result.emplace_back(ext->start, ext->end); + } + } + return result; + } +}; + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. +const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { + const FieldDescriptor** fields = + new const FieldDescriptor*[descriptor->field_count()]; + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + std::sort(fields, fields + descriptor->field_count(), + FieldOrderingByNumber()); + return fields; +} + +// Sort the fields of the given Descriptor by storage size into a new[]'d +// array and return it. +const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) { + const FieldDescriptor** fields = + new const FieldDescriptor*[descriptor->field_count()]; + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + std::sort(fields, fields + descriptor->field_count(), + FieldOrderingByStorageSize()); + return fields; +} + +} // namespace + +MessageGenerator::MessageGenerator(const TProtoStringType& file_description_name, + const Descriptor* descriptor) + : file_description_name_(file_description_name), + descriptor_(descriptor), + field_generators_(descriptor), + class_name_(ClassName(descriptor_)), + deprecated_attribute_(GetOptionalDeprecatedAttribute( + descriptor, descriptor->file(), false, true)) { + for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { + oneof_generators_.push_back( + std::make_unique<OneofGenerator>(descriptor_->oneof_decl(i))); + } + + // Assign has bits: + // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing + // who needs has bits and assigning them. + // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative + // index that groups all the elements in the oneof. + size_t num_has_bits = field_generators_.CalculateHasBits(); + size_t sizeof_has_storage = (num_has_bits + 31) / 32; + if (sizeof_has_storage == 0) { + // In the case where no field needs has bits, don't let the _has_storage_ + // end up as zero length (zero length arrays are sort of a grey area + // since it has to be at the start of the struct). This also ensures a + // field with only oneofs keeps the required negative indices they need. + sizeof_has_storage = 1; + } + // Tell all the fields the oneof base. + for (const auto& generator : oneof_generators_) { + generator->SetOneofIndexBase(sizeof_has_storage); + } + field_generators_.SetOneofIndexBase(sizeof_has_storage); + // sizeof_has_storage needs enough bits for the single fields that aren't in + // any oneof, and then one int32 for each oneof (to store the field number). + sizeof_has_storage += oneof_generators_.size(); + + sizeof_has_storage_ = sizeof_has_storage; +} + +void MessageGenerator::AddExtensionGenerators( + std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators) { + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators->push_back(std::make_unique<ExtensionGenerator>( + class_name_, descriptor_->extension(i))); + extension_generators_.push_back(extension_generators->back().get()); + } +} + +void MessageGenerator::DetermineForwardDeclarations( + y_absl::btree_set<TProtoStringType>* fwd_decls, + bool include_external_types) const { + if (IsMapEntryMessage(descriptor_)) { + return; + } + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* fieldDescriptor = descriptor_->field(i); + field_generators_.get(fieldDescriptor) + .DetermineForwardDeclarations(fwd_decls, include_external_types); + } +} + +void MessageGenerator::DetermineObjectiveCClassDefinitions( + y_absl::btree_set<TProtoStringType>* fwd_decls) const { + if (!IsMapEntryMessage(descriptor_)) { + // Forward declare this class, as a linker symbol, so the symbol can be used + // to reference the class instead of calling +class later. + fwd_decls->insert(ObjCClassDeclaration(class_name_)); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* fieldDescriptor = descriptor_->field(i); + field_generators_.get(fieldDescriptor) + .DetermineObjectiveCClassDefinitions(fwd_decls); + } + } + + const Descriptor* containing_descriptor = descriptor_->containing_type(); + if (containing_descriptor != nullptr) { + TProtoStringType containing_class = ClassName(containing_descriptor); + fwd_decls->insert(ObjCClassDeclaration(containing_class)); + } +} + +void MessageGenerator::GenerateMessageHeader(io::Printer* printer) const { + // This a a map entry message, just recurse and do nothing directly. + if (IsMapEntryMessage(descriptor_)) { + return; + } + + printer->Print( + // clang-format off + "#pragma mark - $classname$\n" + "\n", + // clang-format on + "classname", class_name_); + + if (descriptor_->field_count()) { + std::unique_ptr<const FieldDescriptor*[]> sorted_fields( + SortFieldsByNumber(descriptor_)); + + printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n", "classname", + class_name_); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(sorted_fields[i]) + .GenerateFieldNumberConstant(printer); + } + + printer->Outdent(); + printer->Print("};\n\n"); + } + + for (const auto& generator : oneof_generators_) { + generator->GenerateCaseEnum(printer); + } + + TProtoStringType message_comments; + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + message_comments = BuildCommentsString(location, false); + } else { + message_comments = ""; + } + + printer->Print( + // clang-format off + "$comments$$deprecated_attribute$GPB_FINAL @interface $classname$ : GPBMessage\n\n", + // clang-format on + "classname", class_name_, "deprecated_attribute", deprecated_attribute_, + "comments", message_comments); + + std::vector<char> seen_oneofs(oneof_generators_.size(), 0); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const OneofDescriptor* oneof = field->real_containing_oneof(); + if (oneof) { + const int oneof_index = oneof->index(); + if (!seen_oneofs[oneof_index]) { + seen_oneofs[oneof_index] = 1; + oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration( + printer); + } + } + field_generators_.get(field).GeneratePropertyDeclaration(printer); + } + + printer->Print("@end\n\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateCFunctionDeclarations(printer); + } + + if (!oneof_generators_.empty()) { + for (const auto& generator : oneof_generators_) { + generator->GenerateClearFunctionDeclaration(printer); + } + printer->Print("\n"); + } + + if (descriptor_->extension_count() > 0) { + printer->Print("@interface $classname$ (DynamicMethods)\n\n", "classname", + class_name_); + for (const auto generator : extension_generators_) { + generator->GenerateMembersHeader(printer); + } + printer->Print("@end\n\n"); + } +} + +void MessageGenerator::GenerateSource(io::Printer* printer) const { + if (IsMapEntryMessage(descriptor_)) { + return; + } + printer->Print( + // clang-format off + "#pragma mark - $classname$\n" + "\n", + // clang-format on + "classname", class_name_); + + if (!deprecated_attribute_.empty()) { + // No warnings when compiling the impl of this deprecated class. + // clang-format off + printer->Print( + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n" + "\n"); + // clang-format on + } + + printer->Print("@implementation $classname$\n\n", "classname", class_name_); + + for (const auto& generator : oneof_generators_) { + generator->GeneratePropertyImplementation(printer); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GeneratePropertyImplementation(printer); + } + + std::unique_ptr<const FieldDescriptor*[]> sorted_fields( + SortFieldsByNumber(descriptor_)); + std::unique_ptr<const FieldDescriptor*[]> size_order_fields( + SortFieldsByStorageSize(descriptor_)); + + std::vector<SimpleExtensionRange> sorted_extensions( + SimpleExtensionRange::Normalize(descriptor_)); + + printer->Print( + // clang-format off + "\n" + "typedef struct $classname$__storage_ {\n" + " arc_ui32 _has_storage_[$sizeof_has_storage$];\n", + // clang-format on + "classname", class_name_, "sizeof_has_storage", + y_absl::StrCat(sizeof_has_storage_)); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(size_order_fields[i]) + .GenerateFieldStorageDeclaration(printer); + } + printer->Outdent(); + + printer->Print("} $classname$__storage_;\n\n", "classname", class_name_); + + // clang-format off + printer->Print( + "// This method is threadsafe because it is initially called\n" + "// in +initialize for each subclass.\n" + "+ (GPBDescriptor *)descriptor {\n" + " static GPBDescriptor *descriptor = nil;\n" + " if (!descriptor) {\n"); + // clang-format on + + // If the message scopes extensions, trigger the root class + // +initialize/+extensionRegistry as that is where the runtime support for + // extensions lives. + if (descriptor_->extension_count() > 0) { + // clang-format off + printer->Print( + " // Start up the root class to support the scoped extensions.\n" + " __unused Class rootStartup = [$root_class_name$ class];\n", + "root_class_name", FileClassName(descriptor_->file())); + // clang-format on + } else { + // The Root class has a debug runtime check, so if not starting that + // up, add the check. + printer->Print(" GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"); + } + + TextFormatDecodeData text_format_decode_data; + bool has_fields = descriptor_->field_count() > 0; + bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault(); + TProtoStringType field_description_type; + if (need_defaults) { + field_description_type = "GPBMessageFieldDescriptionWithDefault"; + } else { + field_description_type = "GPBMessageFieldDescription"; + } + if (has_fields) { + printer->Indent(); + printer->Indent(); + printer->Print("static $field_description_type$ fields[] = {\n", + "field_description_type", field_description_type); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); ++i) { + const FieldGenerator& field_generator = + field_generators_.get(sorted_fields[i]); + field_generator.GenerateFieldDescription(printer, need_defaults); + if (field_generator.needs_textformat_name_support()) { + text_format_decode_data.AddString(sorted_fields[i]->number(), + field_generator.generated_objc_name(), + field_generator.raw_field_name()); + } + } + printer->Outdent(); + printer->Print("};\n"); + printer->Outdent(); + printer->Outdent(); + } + + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars; + vars["classname"] = class_name_; + vars["message_name"] = descriptor_->name(); + vars["class_reference"] = ObjCClass(class_name_); + vars["file_description_name"] = file_description_name_; + vars["fields"] = has_fields ? "fields" : "NULL"; + if (has_fields) { + vars["fields_count"] = y_absl::StrCat("(arc_ui32)(sizeof(fields) / sizeof(", + field_description_type, "))"); + } else { + vars["fields_count"] = "0"; + } + + std::vector<TProtoStringType> init_flags; + init_flags.push_back("GPBDescriptorInitializationFlag_UsesClassRefs"); + init_flags.push_back("GPBDescriptorInitializationFlag_Proto3OptionalKnown"); + init_flags.push_back( + "GPBDescriptorInitializationFlag_ClosedEnumSupportKnown"); + if (need_defaults) { + init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault"); + } + if (descriptor_->options().message_set_wire_format()) { + init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat"); + } + vars["init_flags"] = + BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION, init_flags); + + // clang-format off + printer->Print( + vars, + " GPBDescriptor *localDescriptor =\n" + " [GPBDescriptor allocDescriptorForClass:$class_reference$\n" + " messageName:@\"$message_name$\"\n" + " fileDescription:&$file_description_name$\n" + " fields:$fields$\n" + " fieldCount:$fields_count$\n" + " storageSize:sizeof($classname$__storage_)\n" + " flags:$init_flags$];\n"); + // clang-format on + if (!oneof_generators_.empty()) { + printer->Print(" static const char *oneofs[] = {\n"); + for (const auto& generator : oneof_generators_) { + printer->Print(" \"$name$\",\n", "name", + generator->DescriptorName()); + } + printer->Print( + // clang-format off + " };\n" + " [localDescriptor setupOneofs:oneofs\n" + " count:(arc_ui32)(sizeof(oneofs) / sizeof(char*))\n" + " firstHasIndex:$first_has_index$];\n", + // clang-format on + "first_has_index", oneof_generators_[0]->HasIndexAsString()); + } + if (text_format_decode_data.num_entries() != 0) { + const TProtoStringType text_format_data_str(text_format_decode_data.Data()); + // clang-format off + printer->Print( + "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" + " static const char *extraTextFormatInfo ="); + // clang-format on + static const int kBytesPerLine = 40; // allow for escaping + for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) { + printer->Print("\n \"$data$\"", "data", + EscapeTrigraphs(y_absl::CEscape( + text_format_data_str.substr(i, kBytesPerLine)))); + } + // clang-format off + printer->Print( + ";\n" + " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n" + "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"); + // clang-format on + } + if (!sorted_extensions.empty()) { + printer->Print(" static const GPBExtensionRange ranges[] = {\n"); + for (const auto& extension_range : sorted_extensions) { + printer->Print(" { .start = $start$, .end = $end$ },\n", "start", + y_absl::StrCat(extension_range.start), "end", + y_absl::StrCat(extension_range.end)); + } + // clang-format off + printer->Print( + " };\n" + " [localDescriptor setupExtensionRanges:ranges\n" + " count:(arc_ui32)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); + // clang-format on + } + if (descriptor_->containing_type() != nullptr) { + TProtoStringType containing_class = ClassName(descriptor_->containing_type()); + TProtoStringType parent_class_ref = ObjCClass(containing_class); + printer->Print( + // clang-format off + " [localDescriptor setupContainingMessageClass:$parent_class_ref$];\n", + // clang-format on + "parent_class_ref", parent_class_ref); + } + // clang-format off + printer->Print( + " #if defined(DEBUG) && DEBUG\n" + " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" + " #endif // DEBUG\n" + " descriptor = localDescriptor;\n" + " }\n" + " return descriptor;\n" + "}\n\n" + "@end\n\n"); + // clang-format on + + if (!deprecated_attribute_.empty()) { + // clang-format off + printer->Print( + "#pragma clang diagnostic pop\n" + "\n"); + // clang-format on + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateCFunctionImplementations(printer); + } + + for (const auto& generator : oneof_generators_) { + generator->GenerateClearFunctionImplementation(printer); + } +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message.h index 71eec0d0c7..c4698371b7 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message.h @@ -31,13 +31,16 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ +#include <cstddef> +#include <memory> #include <string> -#include <set> #include <vector> -#include <google/protobuf/compiler/objectivec/objectivec_field.h> -#include <google/protobuf/compiler/objectivec/objectivec_oneof.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/io/printer.h> + +#include "y_absl/container/btree_set.h" +#include "google/protobuf/compiler/objectivec/field.h" +#include "google/protobuf/compiler/objectivec/oneof.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -45,50 +48,39 @@ namespace compiler { namespace objectivec { class ExtensionGenerator; -class EnumGenerator; class MessageGenerator { public: - MessageGenerator(const TProtoStringType& root_classname, + MessageGenerator(const TProtoStringType& file_description_name, const Descriptor* descriptor); - ~MessageGenerator(); + ~MessageGenerator() = default; MessageGenerator(const MessageGenerator&) = delete; MessageGenerator& operator=(const MessageGenerator&) = delete; - void GenerateStaticVariablesInitialization(io::Printer* printer); - void GenerateEnumHeader(io::Printer* printer); - void GenerateMessageHeader(io::Printer* printer); - void GenerateSource(io::Printer* printer); - void GenerateExtensionRegistrationSource(io::Printer* printer); - void DetermineObjectiveCClassDefinitions(std::set<TProtoStringType>* fwd_decls); - void DetermineForwardDeclarations(std::set<TProtoStringType>* fwd_decls, - bool include_external_types); + void AddExtensionGenerators( + std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators); + + void GenerateMessageHeader(io::Printer* printer) const; + void GenerateSource(io::Printer* printer) const; + void DetermineObjectiveCClassDefinitions( + y_absl::btree_set<TProtoStringType>* fwd_decls) const; + void DetermineForwardDeclarations(y_absl::btree_set<TProtoStringType>* fwd_decls, + bool include_external_types) const; // Checks if the message or a nested message includes a oneof definition. - bool IncludesOneOfDefinition() const; + bool IncludesOneOfDefinition() const { return !oneof_generators_.empty(); } private: - void GenerateParseFromMethodsHeader(io::Printer* printer); - - void GenerateSerializeOneFieldSource(io::Printer* printer, - const FieldDescriptor* field); - void GenerateSerializeOneExtensionRangeSource( - io::Printer* printer, const Descriptor::ExtensionRange* range); - - void GenerateMessageDescriptionSource(io::Printer* printer); - void GenerateDescriptionOneFieldSource(io::Printer* printer, - const FieldDescriptor* field); - const TProtoStringType root_classname_; + const TProtoStringType file_description_name_; const Descriptor* descriptor_; FieldGeneratorMap field_generators_; const TProtoStringType class_name_; const TProtoStringType deprecated_attribute_; - std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_; - std::vector<std::unique_ptr<EnumGenerator>> enum_generators_; - std::vector<std::unique_ptr<MessageGenerator>> nested_message_generators_; + std::vector<const ExtensionGenerator*> extension_generators_; std::vector<std::unique_ptr<OneofGenerator>> oneof_generators_; + size_t sizeof_has_storage_; }; } // namespace objectivec diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message_field.cc index 8ae073a12a..5156b4f21f 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message_field.cc @@ -28,12 +28,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <map> +#include "google/protobuf/compiler/objectivec/message_field.h" + #include <string> -#include <google/protobuf/compiler/objectivec/objectivec_message_field.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/io/printer.h> +#include "y_absl/container/btree_set.h" +#include "y_absl/container/flat_hash_map.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" namespace google { namespace protobuf { @@ -42,8 +44,9 @@ namespace objectivec { namespace { -void SetMessageVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables) { +void SetMessageVariables( + const FieldDescriptor* descriptor, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables) { const TProtoStringType& message_type = ClassName(descriptor->message_type()); const TProtoStringType& containing_class = ClassName(descriptor->containing_type()); @@ -62,26 +65,24 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor) SetMessageVariables(descriptor, &variables_); } -MessageFieldGenerator::~MessageFieldGenerator() {} - void MessageFieldGenerator::DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, + y_absl::btree_set<TProtoStringType>* fwd_decls, bool include_external_types) const { - ObjCObjFieldGenerator::DetermineForwardDeclarations( - fwd_decls, include_external_types); + ObjCObjFieldGenerator::DetermineForwardDeclarations(fwd_decls, + include_external_types); // Within a file there is no requirement on the order of the messages, so // local references need a forward declaration. External files (not WKTs), // need one when requested. - if ((include_external_types && - !IsProtobufLibraryBundledProtoFile(descriptor_->message_type()->file())) || + if ((include_external_types && !IsProtobufLibraryBundledProtoFile( + descriptor_->message_type()->file())) || descriptor_->file() == descriptor_->message_type()->file()) { // Class name is already in "storage_type". - fwd_decls->insert("@class " + variable("storage_type")); + fwd_decls->insert(y_absl::StrCat("@class ", variable("storage_type"), ";")); } } void MessageFieldGenerator::DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) const { + y_absl::btree_set<TProtoStringType>* fwd_decls) const { fwd_decls->insert(ObjCClassDeclaration(variable("storage_type"))); } @@ -89,31 +90,30 @@ RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( const FieldDescriptor* descriptor) : RepeatedFieldGenerator(descriptor) { SetMessageVariables(descriptor, &variables_); + TProtoStringType storage_type = variables_["storage_type"]; variables_["array_storage_type"] = "NSMutableArray"; variables_["array_property_type"] = - "NSMutableArray<" + variables_["storage_type"] + "*>"; + y_absl::StrCat("NSMutableArray<", storage_type, "*>"); } -RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} - void RepeatedMessageFieldGenerator::DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, + y_absl::btree_set<TProtoStringType>* fwd_decls, bool include_external_types) const { - RepeatedFieldGenerator::DetermineForwardDeclarations( - fwd_decls, include_external_types); + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls, + include_external_types); // Within a file there is no requirement on the order of the messages, so // local references need a forward declaration. External files (not WKTs), // need one when requested. - if ((include_external_types && - !IsProtobufLibraryBundledProtoFile(descriptor_->message_type()->file())) || + if ((include_external_types && !IsProtobufLibraryBundledProtoFile( + descriptor_->message_type()->file())) || descriptor_->file() == descriptor_->message_type()->file()) { // Class name is already in "storage_type". - fwd_decls->insert("@class " + variable("storage_type")); + fwd_decls->insert(y_absl::StrCat("@class ", variable("storage_type"), ";")); } } void RepeatedMessageFieldGenerator::DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) const { + y_absl::btree_set<TProtoStringType>* fwd_decls) const { fwd_decls->insert(ObjCClassDeclaration(variable("storage_type"))); } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message_field.h index 50ddb633cc..303b69a7c6 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/message_field.h @@ -31,9 +31,10 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__ -#include <map> #include <string> -#include <google/protobuf/compiler/objectivec/objectivec_field.h> + +#include "y_absl/container/btree_set.h" +#include "google/protobuf/compiler/objectivec/field.h" namespace google { namespace protobuf { @@ -45,18 +46,16 @@ class MessageFieldGenerator : public ObjCObjFieldGenerator { protected: explicit MessageFieldGenerator(const FieldDescriptor* descriptor); + ~MessageFieldGenerator() override = default; MessageFieldGenerator(const MessageFieldGenerator&) = delete; MessageFieldGenerator& operator=(const MessageFieldGenerator&) = delete; - virtual ~MessageFieldGenerator(); - public: - virtual void DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, - bool include_external_types) const override; - virtual void DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) const override; + void DetermineForwardDeclarations(y_absl::btree_set<TProtoStringType>* fwd_decls, + bool include_external_types) const override; + void DetermineObjectiveCClassDefinitions( + y_absl::btree_set<TProtoStringType>* fwd_decls) const override; }; class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { @@ -64,17 +63,17 @@ class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { protected: explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor); - virtual ~RepeatedMessageFieldGenerator(); + ~RepeatedMessageFieldGenerator() override = default; RepeatedMessageFieldGenerator(const RepeatedMessageFieldGenerator&) = delete; - RepeatedMessageFieldGenerator operator=(const RepeatedMessageFieldGenerator&) = delete; + RepeatedMessageFieldGenerator operator=( + const RepeatedMessageFieldGenerator&) = delete; public: - virtual void DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, - bool include_external_types) const override; - virtual void DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) const override; + void DetermineForwardDeclarations(y_absl::btree_set<TProtoStringType>* fwd_decls, + bool include_external_types) const override; + void DetermineObjectiveCClassDefinitions( + y_absl::btree_set<TProtoStringType>* fwd_decls) const override; }; } // namespace objectivec diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/names.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/names.cc new file mode 100644 index 0000000000..3a3ee8ffd0 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/names.cc @@ -0,0 +1,1247 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/names.h" + +#include <algorithm> +#include <climits> +#include <fstream> +#include <iostream> +#include <ostream> +#include <sstream> +#include <string> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/str_split.h" +#include "google/protobuf/compiler/code_generator.h" +#include "google/protobuf/compiler/objectivec/line_consumer.h" +#include "google/protobuf/compiler/objectivec/nsobject_methods.h" +#include "google/protobuf/descriptor.pb.h" + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +bool BoolFromEnvVar(const char* env_var, bool default_value) { + const char* value = getenv(env_var); + if (value) { + return TProtoStringType("YES") == y_absl::AsciiStrToUpper(value); + } + return default_value; +} + +class SimpleLineCollector : public LineConsumer { + public: + explicit SimpleLineCollector(y_absl::flat_hash_set<TProtoStringType>* inout_set) + : set_(inout_set) {} + + bool ConsumeLine(y_absl::string_view line, TProtoStringType* out_error) override { + set_->insert(TProtoStringType(line)); + return true; + } + + private: + y_absl::flat_hash_set<TProtoStringType>* set_; +}; + +class PackageToPrefixesCollector : public LineConsumer { + public: + PackageToPrefixesCollector(y_absl::string_view usage, + y_absl::flat_hash_map<TProtoStringType, TProtoStringType>* + inout_package_to_prefix_map) + : usage_(usage), prefix_map_(inout_package_to_prefix_map) {} + + bool ConsumeLine(y_absl::string_view line, TProtoStringType* out_error) override; + + private: + const TProtoStringType usage_; + y_absl::flat_hash_map<TProtoStringType, TProtoStringType>* prefix_map_; +}; + +class PrefixModeStorage { + public: + PrefixModeStorage(); + + y_absl::string_view package_to_prefix_mappings_path() const { + return package_to_prefix_mappings_path_; + } + void set_package_to_prefix_mappings_path(y_absl::string_view path) { + package_to_prefix_mappings_path_ = TProtoStringType(path); + package_to_prefix_map_.clear(); + } + + y_absl::string_view prefix_from_proto_package_mappings( + const FileDescriptor* file); + + bool use_package_name() const { return use_package_name_; } + void set_use_package_name(bool on_or_off) { use_package_name_ = on_or_off; } + + y_absl::string_view exception_path() const { return exception_path_; } + void set_exception_path(y_absl::string_view path) { + exception_path_ = TProtoStringType(path); + exceptions_.clear(); + } + + bool is_package_exempted(y_absl::string_view package); + + // When using a proto package as the prefix, this should be added as the + // prefix in front of it. + y_absl::string_view forced_package_prefix() const { return forced_prefix_; } + void set_forced_package_prefix(y_absl::string_view prefix) { + forced_prefix_ = TProtoStringType(prefix); + } + + private: + bool use_package_name_; + y_absl::flat_hash_map<TProtoStringType, TProtoStringType> package_to_prefix_map_; + TProtoStringType package_to_prefix_mappings_path_; + TProtoStringType exception_path_; + TProtoStringType forced_prefix_; + y_absl::flat_hash_set<TProtoStringType> exceptions_; +}; + +PrefixModeStorage::PrefixModeStorage() { + // Even thought there are generation options, have an env back door since some + // of these helpers could be used in other plugins. + + use_package_name_ = BoolFromEnvVar("GPB_OBJC_USE_PACKAGE_AS_PREFIX", false); + + const char* exception_path = + getenv("GPB_OBJC_PACKAGE_PREFIX_EXCEPTIONS_PATH"); + if (exception_path) { + exception_path_ = exception_path; + } + + const char* prefix = getenv("GPB_OBJC_USE_PACKAGE_AS_PREFIX_PREFIX"); + if (prefix) { + forced_prefix_ = prefix; + } +} + +constexpr y_absl::string_view kNoPackagePrefix = "no_package:"; + +y_absl::string_view PrefixModeStorage::prefix_from_proto_package_mappings( + const FileDescriptor* file) { + if (!file) { + return ""; + } + + if (package_to_prefix_map_.empty() && + !package_to_prefix_mappings_path_.empty()) { + TProtoStringType error_str; + // Re use the same collector as we use for expected_prefixes_path since the + // file format is the same. + PackageToPrefixesCollector collector("Package to prefixes", + &package_to_prefix_map_); + if (!ParseSimpleFile(package_to_prefix_mappings_path_, &collector, + &error_str)) { + if (error_str.empty()) { + error_str = y_absl::StrCat("protoc:0: warning: Failed to parse ", + "prefix to proto package mappings file: ", + package_to_prefix_mappings_path_); + } + std::cerr << error_str << std::endl; + std::cerr.flush(); + package_to_prefix_map_.clear(); + } + } + + const TProtoStringType package = file->package(); + // For files without packages, the can be registered as "no_package:PATH", + // allowing the expected prefixes file. + const TProtoStringType lookup_key = + package.empty() ? y_absl::StrCat(kNoPackagePrefix, file->name()) : package; + + auto prefix_lookup = package_to_prefix_map_.find(lookup_key); + + if (prefix_lookup != package_to_prefix_map_.end()) { + return prefix_lookup->second; + } + + return ""; +} + +bool PrefixModeStorage::is_package_exempted(y_absl::string_view package) { + if (exceptions_.empty() && !exception_path_.empty()) { + TProtoStringType error_str; + SimpleLineCollector collector(&exceptions_); + if (!ParseSimpleFile(exception_path_, &collector, &error_str)) { + if (error_str.empty()) { + error_str = TProtoStringType("protoc:0: warning: Failed to parse") + + TProtoStringType(" package prefix exceptions file: ") + + exception_path_; + } + std::cerr << error_str << std::endl; + std::cerr.flush(); + exceptions_.clear(); + } + + // If the file was empty put something in it so it doesn't get reloaded over + // and over. + if (exceptions_.empty()) { + exceptions_.insert("<not a real package>"); + } + } + + return exceptions_.contains(package); +} + +PrefixModeStorage& g_prefix_mode = *new PrefixModeStorage(); + +} // namespace + +y_absl::string_view GetPackageToPrefixMappingsPath() { + return g_prefix_mode.package_to_prefix_mappings_path(); +} + +void SetPackageToPrefixMappingsPath(y_absl::string_view file_path) { + g_prefix_mode.set_package_to_prefix_mappings_path(file_path); +} + +bool UseProtoPackageAsDefaultPrefix() { + return g_prefix_mode.use_package_name(); +} + +void SetUseProtoPackageAsDefaultPrefix(bool on_or_off) { + g_prefix_mode.set_use_package_name(on_or_off); +} + +y_absl::string_view GetProtoPackagePrefixExceptionList() { + return g_prefix_mode.exception_path(); +} + +void SetProtoPackagePrefixExceptionList(y_absl::string_view file_path) { + g_prefix_mode.set_exception_path(file_path); +} + +y_absl::string_view GetForcedPackagePrefix() { + return g_prefix_mode.forced_package_prefix(); +} + +void SetForcedPackagePrefix(y_absl::string_view prefix) { + g_prefix_mode.set_forced_package_prefix(prefix); +} + +namespace { + +const char* const kUpperSegmentsList[] = {"url", "http", "https"}; + +const y_absl::flat_hash_set<y_absl::string_view>& UpperSegments() { + static const auto* words = [] { + auto* words = new y_absl::flat_hash_set<y_absl::string_view>(); + + for (const auto word : kUpperSegmentsList) { + words->emplace(word); + } + return words; + }(); + return *words; +} + +// Internal helper for name handing. +// Do not expose this outside of helpers, stick to having functions for specific +// cases (ClassName(), FieldName()), so there is always consistent suffix rules. +TProtoStringType UnderscoresToCamelCase(y_absl::string_view input, + bool first_capitalized) { + std::vector<TProtoStringType> values; + TProtoStringType current; + + bool last_char_was_number = false; + bool last_char_was_lower = false; + bool last_char_was_upper = false; + for (int i = 0; i < input.size(); i++) { + char c = input[i]; + if (y_absl::ascii_isdigit(c)) { + if (!last_char_was_number) { + values.push_back(current); + current = ""; + } + current += c; + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_number = true; + } else if (y_absl::ascii_islower(c)) { + // lowercase letter can follow a lowercase or uppercase letter + if (!last_char_was_lower && !last_char_was_upper) { + values.push_back(current); + current = ""; + } + current += c; // already lower + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_lower = true; + } else if (y_absl::ascii_isupper(c)) { + if (!last_char_was_upper) { + values.push_back(current); + current = ""; + } + current += y_absl::ascii_tolower(c); + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_upper = true; + } else { + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + } + } + values.push_back(current); + + TProtoStringType result; + bool first_segment_forces_upper = false; + for (auto& value : values) { + bool all_upper = UpperSegments().contains(value); + if (all_upper && (result.length() == 0)) { + first_segment_forces_upper = true; + } + if (all_upper) { + y_absl::AsciiStrToUpper(&value); + } else { + value[0] = y_absl::ascii_toupper(value[0]); + } + result += value; + } + if ((result.length() != 0) && !first_capitalized && + !first_segment_forces_upper) { + result[0] = y_absl::ascii_tolower(result[0]); + } + return result; +} + +const char* const kReservedWordList[] = { + // Note NSObject Methods: + // These are brought in from nsobject_methods.h that is generated + // using method_dump.sh. See kNSObjectMethods below. + + // Objective-C "keywords" that aren't in C + // From + // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c + // with some others added on. + "id", + "_cmd", + "super", + "in", + "out", + "inout", + "bycopy", + "byref", + "oneway", + "self", + "instancetype", + "nullable", + "nonnull", + "nil", + "Nil", + "YES", + "NO", + "weak", + + // C/C++ keywords (Incl C++ 0x11) + // From http://en.cppreference.com/w/cpp/keywords + "and", + "and_eq", + "alignas", + "alignof", + "asm", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "const", + "constexpr", + "const_cast", + "continue", + "decltype", + "default", + "delete", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern ", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + + // C99 keywords + // From + // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm + "restrict", + + // GCC/Clang extension + "typeof", + + // Not a keyword, but will break you + "NULL", + + // C88+ specs call for these to be macros, so depending on what they are + // defined to be it can lead to odd errors for some Xcode/SDK versions. + "stdin", + "stdout", + "stderr", + + // Objective-C Runtime typedefs + // From <obc/runtime.h> + "Category", + "Ivar", + "Method", + "Protocol", + + // GPBMessage Methods + // Only need to add instance methods that may conflict with + // method declared in protos. The main cases are methods + // that take no arguments, or setFoo:/hasFoo: type methods. + "clear", + "data", + "delimitedData", + "descriptor", + "extensionRegistry", + "extensionsCurrentlySet", + "initialized", + "isInitialized", + "serializedSize", + "sortedExtensionsInUse", + "unknownFields", + + // MacTypes.h names + "Fixed", + "Fract", + "Size", + "LogicalAddress", + "PhysicalAddress", + "ByteCount", + "ByteOffset", + "Duration", + "AbsoluteTime", + "OptionBits", + "ItemCount", + "PBVersion", + "ScriptCode", + "LangCode", + "RegionCode", + "OSType", + "ProcessSerialNumber", + "Point", + "Rect", + "FixedPoint", + "FixedRect", + "Style", + "StyleParameter", + "StyleField", + "TimeScale", + "TimeBase", + "TimeRecord", +}; + +const y_absl::flat_hash_set<y_absl::string_view>& ReservedWords() { + static const auto* words = [] { + auto* words = new y_absl::flat_hash_set<y_absl::string_view>(); + + for (const auto word : kReservedWordList) { + words->emplace(word); + } + return words; + }(); + return *words; +} + +const y_absl::flat_hash_set<y_absl::string_view>& NSObjectMethods() { + static const auto* words = [] { + auto* words = new y_absl::flat_hash_set<y_absl::string_view>(); + + for (const auto word : kNSObjectMethodsList) { + words->emplace(word); + } + return words; + }(); + return *words; +} + +// returns true is input starts with __ or _[A-Z] which are reserved identifiers +// in C/ C++. All calls should go through UnderscoresToCamelCase before getting +// here but this verifies and allows for future expansion if we decide to +// redefine what a reserved C identifier is (for example the GNU list +// https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html ) +bool IsReservedCIdentifier(y_absl::string_view input) { + if (input.length() > 2) { + if (input.at(0) == '_') { + if (isupper(input.at(1)) || input.at(1) == '_') { + return true; + } + } + } + return false; +} + +TProtoStringType SanitizeNameForObjC(y_absl::string_view prefix, + y_absl::string_view input, + y_absl::string_view extension, + TProtoStringType* out_suffix_added) { + TProtoStringType sanitized; + // We add the prefix in the cases where the string is missing a prefix. + // We define "missing a prefix" as where 'input': + // a) Doesn't start with the prefix or + // b) Isn't equivalent to the prefix or + // c) Has the prefix, but the letter after the prefix is lowercase + if (y_absl::StartsWith(input, prefix)) { + if (input.length() == prefix.length() || + !y_absl::ascii_isupper(input[prefix.length()])) { + sanitized = y_absl::StrCat(prefix, input); + } else { + sanitized = TProtoStringType(input); + } + } else { + sanitized = y_absl::StrCat(prefix, input); + } + if (IsReservedCIdentifier(sanitized) || ReservedWords().contains(sanitized) || + NSObjectMethods().contains(sanitized)) { + if (out_suffix_added) *out_suffix_added = TProtoStringType(extension); + return y_absl::StrCat(sanitized, extension); + } + if (out_suffix_added) out_suffix_added->clear(); + return sanitized; +} + +TProtoStringType NameFromFieldDescriptor(const FieldDescriptor* field) { + if (field->type() == FieldDescriptor::TYPE_GROUP) { + return field->message_type()->name(); + } else { + return field->name(); + } +} + +void PathSplit(y_absl::string_view path, TProtoStringType* directory, + TProtoStringType* basename) { + y_absl::string_view::size_type last_slash = path.rfind('/'); + if (last_slash == y_absl::string_view::npos) { + if (directory) { + *directory = ""; + } + if (basename) { + *basename = TProtoStringType(path); + } + } else { + if (directory) { + *directory = TProtoStringType(path.substr(0, last_slash)); + } + if (basename) { + *basename = TProtoStringType(path.substr(last_slash + 1)); + } + } +} + +bool IsSpecialNamePrefix(y_absl::string_view name, + const std::vector<TProtoStringType>& special_names) { + for (const auto& special_name : special_names) { + const size_t length = special_name.length(); + if (name.compare(0, length, special_name) == 0) { + if (name.length() > length) { + // If name is longer than the special_name that it matches the next + // character must be not lower case (newton vs newTon vs new_ton). + return !y_absl::ascii_islower(name[length]); + } else { + return true; + } + } + } + return false; +} + +void MaybeUnQuote(y_absl::string_view* input) { + if ((input->length() >= 2) && + ((*input->data() == '\'' || *input->data() == '"')) && + ((*input)[input->length() - 1] == *input->data())) { + input->remove_prefix(1); + input->remove_suffix(1); + } +} + +} // namespace + +bool IsRetainedName(y_absl::string_view name) { + // List of prefixes from + // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html + static const std::vector<TProtoStringType>* retained_names = + new std::vector<TProtoStringType>({"new", "alloc", "copy", "mutableCopy"}); + return IsSpecialNamePrefix(name, *retained_names); +} + +bool IsInitName(y_absl::string_view name) { + static const std::vector<TProtoStringType>* init_names = + new std::vector<TProtoStringType>({"init"}); + return IsSpecialNamePrefix(name, *init_names); +} + +bool IsCreateName(y_absl::string_view name) { + // List of segments from + // https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-103029 + static const std::vector<TProtoStringType>* create_names = + new std::vector<TProtoStringType>({"Create", "Copy"}); + + for (const auto& create_name : *create_names) { + const size_t length = create_name.length(); + size_t pos = name.find(create_name); + if (pos != TProtoStringType::npos) { + // The above docs don't actually call out anything about the characters + // before the special words. So it's not clear if something like + // "FOOCreate" would or would not match the "The Create Rule", but by not + // checking, and claiming it does match, then callers will annotate with + // `cf_returns_not_retained` which will ensure things work as desired. + // + // The footnote here is the docs do have a passing reference to "NoCopy", + // but again, not looking for that and just returning `true` will cause + // callers to annotate the api as not being a Create Rule function. + + // If name is longer than the create_names[i] that it matches the next + // character must be not lower case (Copyright vs CopyFoo vs Copy_Foo). + if (name.length() > pos + length) { + return !y_absl::ascii_islower(name[pos + length]); + } else { + return true; + } + } + } + return false; +} + +TProtoStringType BaseFileName(const FileDescriptor* file) { + TProtoStringType basename; + PathSplit(file->name(), nullptr, &basename); + return basename; +} + +TProtoStringType FileClassPrefix(const FileDescriptor* file) { + // Always honor the file option. + if (file->options().has_objc_class_prefix()) { + return file->options().objc_class_prefix(); + } + + // If package prefix is specified in an prefix to proto mappings file then use + // that. + y_absl::string_view objc_class_prefix = + g_prefix_mode.prefix_from_proto_package_mappings(file); + if (!objc_class_prefix.empty()) { + return TProtoStringType(objc_class_prefix); + } + + // If package prefix isn't enabled, done. + if (!g_prefix_mode.use_package_name()) { + return ""; + } + + // If the package is in the exceptions list, done. + if (g_prefix_mode.is_package_exempted(file->package())) { + return ""; + } + + // Transform the package into a prefix: use the dot segments as part, + // camelcase each one and then join them with underscores, and add an + // underscore at the end. + TProtoStringType result; + const std::vector<TProtoStringType> segments = + y_absl::StrSplit(file->package(), '.', y_absl::SkipEmpty()); + for (const auto& segment : segments) { + const TProtoStringType part = UnderscoresToCamelCase(segment, true); + if (part.empty()) { + continue; + } + if (!result.empty()) { + result.append("_"); + } + result.append(part); + } + if (!result.empty()) { + result.append("_"); + } + return y_absl::StrCat(g_prefix_mode.forced_package_prefix(), result); +} + +TProtoStringType FilePath(const FileDescriptor* file) { + TProtoStringType output; + TProtoStringType basename; + TProtoStringType directory; + PathSplit(file->name(), &directory, &basename); + if (directory.length() > 0) { + output = y_absl::StrCat(directory, "/"); + } + basename = StripProto(basename); + + // CamelCase to be more ObjC friendly. + basename = UnderscoresToCamelCase(basename, true); + + return y_absl::StrCat(output, basename); +} + +TProtoStringType FilePathBasename(const FileDescriptor* file) { + TProtoStringType output; + TProtoStringType basename; + TProtoStringType directory; + PathSplit(file->name(), &directory, &basename); + basename = StripProto(basename); + + // CamelCase to be more ObjC friendly. + output = UnderscoresToCamelCase(basename, true); + + return output; +} + +TProtoStringType FileClassName(const FileDescriptor* file) { + const TProtoStringType prefix = FileClassPrefix(file); + const TProtoStringType name = y_absl::StrCat( + UnderscoresToCamelCase(StripProto(BaseFileName(file)), true), "Root"); + // There aren't really any reserved words that end in "Root", but playing + // it safe and checking. + return SanitizeNameForObjC(prefix, name, "_RootClass", nullptr); +} + +TProtoStringType ClassNameWorker(const Descriptor* descriptor) { + TProtoStringType name; + if (descriptor->containing_type() != nullptr) { + return y_absl::StrCat(ClassNameWorker(descriptor->containing_type()), "_", + descriptor->name()); + } + return y_absl::StrCat(name, descriptor->name()); +} + +TProtoStringType ClassNameWorker(const EnumDescriptor* descriptor) { + TProtoStringType name; + if (descriptor->containing_type() != nullptr) { + return y_absl::StrCat(ClassNameWorker(descriptor->containing_type()), "_", + descriptor->name()); + } + return y_absl::StrCat(name, descriptor->name()); +} + +TProtoStringType ClassName(const Descriptor* descriptor) { + return ClassName(descriptor, nullptr); +} + +TProtoStringType ClassName(const Descriptor* descriptor, + TProtoStringType* out_suffix_added) { + // 1. Message names are used as is (style calls for CamelCase, trust it). + // 2. Check for reserved word at the very end and then suffix things. + const TProtoStringType prefix = FileClassPrefix(descriptor->file()); + const TProtoStringType name = ClassNameWorker(descriptor); + return SanitizeNameForObjC(prefix, name, "_Class", out_suffix_added); +} + +TProtoStringType EnumName(const EnumDescriptor* descriptor) { + // 1. Enum names are used as is (style calls for CamelCase, trust it). + // 2. Check for reserved word at the every end and then suffix things. + // message Fixed { + // message Size {...} + // enum Mumble {...} + // ... + // } + // yields Fixed_Class, Fixed_Size. + const TProtoStringType prefix = FileClassPrefix(descriptor->file()); + const TProtoStringType name = ClassNameWorker(descriptor); + return SanitizeNameForObjC(prefix, name, "_Enum", nullptr); +} + +TProtoStringType EnumValueName(const EnumValueDescriptor* descriptor) { + // Because of the Switch enum compatibility, the name on the enum has to have + // the suffix handing, so it slightly diverges from how nested classes work. + // enum Fixed { + // FOO = 1 + // } + // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo). + const TProtoStringType class_name = EnumName(descriptor->type()); + const TProtoStringType value_str = + UnderscoresToCamelCase(descriptor->name(), true); + const TProtoStringType name = y_absl::StrCat(class_name, "_", value_str); + // There aren't really any reserved words with an underscore and a leading + // capital letter, but playing it safe and checking. + return SanitizeNameForObjC("", name, "_Value", nullptr); +} + +TProtoStringType EnumValueShortName(const EnumValueDescriptor* descriptor) { + // Enum value names (EnumValueName above) are the enum name turned into + // a class name and then the value name is CamelCased and concatenated; the + // whole thing then gets sanitized for reserved words. + // The "short name" is intended to be the final leaf, the value name; but + // you can't simply send that off to sanitize as that could result in it + // getting modified when the full name didn't. For example enum + // "StorageModes" has a value "retain". So the full name is + // "StorageModes_Retain", but if we sanitize "retain" it would become + // "RetainValue". + // So the right way to get the short name is to take the full enum name + // and then strip off the enum name (leaving the value name and anything + // done by sanitize). + const TProtoStringType class_name = EnumName(descriptor->type()); + const TProtoStringType long_name_prefix = y_absl::StrCat(class_name, "_"); + const TProtoStringType long_name = EnumValueName(descriptor); + return TProtoStringType(y_absl::StripPrefix(long_name, long_name_prefix)); +} + +TProtoStringType UnCamelCaseEnumShortName(y_absl::string_view name) { + TProtoStringType result; + for (int i = 0; i < name.size(); i++) { + char c = name[i]; + if (i > 0 && y_absl::ascii_isupper(c)) { + result += '_'; + } + result += y_absl::ascii_toupper(c); + } + return result; +} + +TProtoStringType ExtensionMethodName(const FieldDescriptor* descriptor) { + const TProtoStringType name = NameFromFieldDescriptor(descriptor); + const TProtoStringType result = UnderscoresToCamelCase(name, false); + return SanitizeNameForObjC("", result, "_Extension", nullptr); +} + +TProtoStringType FieldName(const FieldDescriptor* field) { + const TProtoStringType name = NameFromFieldDescriptor(field); + TProtoStringType result = UnderscoresToCamelCase(name, false); + if (field->is_repeated() && !field->is_map()) { + // Add "Array" before do check for reserved worlds. + y_absl::StrAppend(&result, "Array"); + } else { + // If it wasn't repeated, but ends in "Array", force on the _p suffix. + if (y_absl::EndsWith(result, "Array")) { + y_absl::StrAppend(&result, "_p"); + } + } + return SanitizeNameForObjC("", result, "_p", nullptr); +} + +TProtoStringType FieldNameCapitalized(const FieldDescriptor* field) { + // Want the same suffix handling, so upcase the first letter of the other + // name. + TProtoStringType result = FieldName(field); + if (result.length() > 0) { + result[0] = y_absl::ascii_toupper(result[0]); + } + return result; +} + +TProtoStringType OneofEnumName(const OneofDescriptor* descriptor) { + const Descriptor* fieldDescriptor = descriptor->containing_type(); + TProtoStringType name = y_absl::StrCat( + ClassName(fieldDescriptor), "_", + UnderscoresToCamelCase(descriptor->name(), true), "_OneOfCase"); + // No sanitize needed because the OS never has names that end in _OneOfCase. + return name; +} + +TProtoStringType OneofName(const OneofDescriptor* descriptor) { + TProtoStringType name = UnderscoresToCamelCase(descriptor->name(), false); + // No sanitize needed because it gets OneOfCase added and that shouldn't + // ever conflict. + return name; +} + +TProtoStringType OneofNameCapitalized(const OneofDescriptor* descriptor) { + // Use the common handling and then up-case the first letter. + TProtoStringType result = OneofName(descriptor); + if (result.length() > 0) { + result[0] = y_absl::ascii_toupper(result[0]); + } + return result; +} + +TProtoStringType UnCamelCaseFieldName(y_absl::string_view name, + const FieldDescriptor* field) { + y_absl::string_view worker(name); + if (y_absl::EndsWith(worker, "_p")) { + worker = y_absl::StripSuffix(worker, "_p"); + } + if (field->is_repeated() && y_absl::EndsWith(worker, "Array")) { + worker = y_absl::StripSuffix(worker, "Array"); + } + if (field->type() == FieldDescriptor::TYPE_GROUP) { + if (worker.length() > 0) { + if (y_absl::ascii_islower(worker[0])) { + TProtoStringType copy(worker); + copy[0] = y_absl::ascii_toupper(worker[0]); + return copy; + } + } + return TProtoStringType(worker); + } else { + TProtoStringType result; + for (int i = 0; i < worker.size(); i++) { + char c = worker[i]; + if (y_absl::ascii_isupper(c)) { + if (i > 0) { + result += '_'; + } + result += y_absl::ascii_tolower(c); + } else { + result += c; + } + } + return result; + } +} + +// Making these a generator option for folks that don't use CocoaPods, but do +// want to put the library in a framework is an interesting question. The +// problem is it means changing sources shipped with the library to actually +// use a different value; so it isn't as simple as a option. +const char* const ProtobufLibraryFrameworkName = "Protobuf"; + +TProtoStringType ProtobufFrameworkImportSymbol(y_absl::string_view framework_name) { + // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS + return y_absl::StrCat("GPB_USE_", y_absl::AsciiStrToUpper(framework_name), + "_FRAMEWORK_IMPORTS"); +} + +bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) { + // We don't check the name prefix or proto package because some files + // (descriptor.proto), aren't shipped generated by the library, so this + // seems to be the safest way to only catch the ones shipped. + const TProtoStringType name = file->name(); + if (name == "google/protobuf/any.proto" || + name == "google/protobuf/api.proto" || + name == "google/protobuf/duration.proto" || + name == "google/protobuf/empty.proto" || + name == "google/protobuf/field_mask.proto" || + name == "google/protobuf/source_context.proto" || + name == "google/protobuf/struct.proto" || + name == "google/protobuf/timestamp.proto" || + name == "google/protobuf/type.proto" || + name == "google/protobuf/wrappers.proto") { + return true; + } + return false; +} + +namespace { + +bool PackageToPrefixesCollector::ConsumeLine(y_absl::string_view line, + TProtoStringType* out_error) { + int offset = line.find('='); + if (offset == y_absl::string_view::npos) { + *out_error = + y_absl::StrCat(usage_, " file line without equal sign: '", line, "'."); + return false; + } + y_absl::string_view package = + y_absl::StripAsciiWhitespace(line.substr(0, offset)); + y_absl::string_view prefix = + y_absl::StripAsciiWhitespace(line.substr(offset + 1)); + MaybeUnQuote(&prefix); + // Don't really worry about error checking the package/prefix for + // being valid. Assume the file is validated when it is created/edited. + (*prefix_map_)[package] = TProtoStringType(prefix); + return true; +} + +bool LoadExpectedPackagePrefixes( + y_absl::string_view expected_prefixes_path, + y_absl::flat_hash_map<TProtoStringType, TProtoStringType>* prefix_map, + TProtoStringType* out_error) { + if (expected_prefixes_path.empty()) { + return true; + } + + PackageToPrefixesCollector collector("Expected prefixes", prefix_map); + return ParseSimpleFile(expected_prefixes_path, &collector, out_error); +} + +bool ValidateObjCClassPrefix( + const FileDescriptor* file, y_absl::string_view expected_prefixes_path, + const y_absl::flat_hash_map<TProtoStringType, TProtoStringType>& + expected_package_prefixes, + bool prefixes_must_be_registered, bool require_prefixes, + TProtoStringType* out_error) { + // Reminder: An explicit prefix option of "" is valid in case the default + // prefixing is set to use the proto package and a file needs to be generated + // without any prefix at all (for legacy reasons). + + bool has_prefix = file->options().has_objc_class_prefix(); + bool have_expected_prefix_file = !expected_prefixes_path.empty(); + + const TProtoStringType prefix = file->options().objc_class_prefix(); + const TProtoStringType package = file->package(); + // For files without packages, the can be registered as "no_package:PATH", + // allowing the expected prefixes file. + const TProtoStringType lookup_key = + package.empty() ? y_absl::StrCat(kNoPackagePrefix, file->name()) : package; + + // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some + // error cases, so it seems to be ok to use as a back door for warnings. + + // Check: Error - See if there was an expected prefix for the package and + // report if it doesn't match (wrong or missing). + auto package_match = expected_package_prefixes.find(lookup_key); + if (package_match != expected_package_prefixes.end()) { + // There was an entry, and... + if (has_prefix && package_match->second == prefix) { + // ...it matches. All good, out of here! + return true; + } else { + // ...it didn't match! + *out_error = + y_absl::StrCat("error: Expected 'option objc_class_prefix = \"", + package_match->second, "\";'"); + if (!package.empty()) { + y_absl::StrAppend(out_error, " for package '", package, "'"); + } + y_absl::StrAppend(out_error, " in '", file->name(), "'"); + if (has_prefix) { + y_absl::StrAppend(out_error, "; but found '", prefix, "' instead"); + } + y_absl::StrAppend(out_error, "."); + return false; + } + } + + // If there was no prefix option, we're done at this point. + if (!has_prefix) { + if (require_prefixes) { + *out_error = y_absl::StrCat("error: '", file->name(), + "' does not have a required 'option" + " objc_class_prefix'."); + return false; + } + return true; + } + + // When the prefix is non empty, check it against the expected entries. + if (!prefix.empty() && have_expected_prefix_file) { + // For a non empty prefix, look for any other package that uses the prefix. + TProtoStringType other_package_for_prefix; + for (auto i = expected_package_prefixes.begin(); + i != expected_package_prefixes.end(); ++i) { + if (i->second == prefix) { + other_package_for_prefix = i->first; + // Stop on the first real package listing, if it was a no_package file + // specific entry, keep looking to try and find a package one. + if (!y_absl::StartsWith(other_package_for_prefix, kNoPackagePrefix)) { + break; + } + } + } + + // Check: Error - Make sure the prefix wasn't expected for a different + // package (overlap is allowed, but it has to be listed as an expected + // overlap). + if (!other_package_for_prefix.empty()) { + *out_error = y_absl::StrCat("error: Found 'option objc_class_prefix = \"", + prefix, "\";' in '", file->name(), + "'; that prefix is already used for "); + if (y_absl::StartsWith(other_package_for_prefix, kNoPackagePrefix)) { + y_absl::StrAppend( + out_error, "file '", + y_absl::StripPrefix(other_package_for_prefix, kNoPackagePrefix), + "'."); + } else { + y_absl::StrAppend(out_error, "'package ", other_package_for_prefix, + ";'."); + } + y_absl::StrAppend(out_error, " It can only be reused by adding '", + lookup_key, " = ", prefix, + "' to the expected prefixes file (", + expected_prefixes_path, ")."); + return false; // Only report first usage of the prefix. + } + } // !prefix.empty() && have_expected_prefix_file + + // Check: Warning - Make sure the prefix is is a reasonable value according + // to Apple's rules (the checks above implicitly whitelist anything that + // doesn't meet these rules). + if (!prefix.empty() && !y_absl::ascii_isupper(prefix[0])) { + std::cerr << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " it should start with a capital letter." << std::endl; + std::cerr.flush(); + } + if (!prefix.empty() && prefix.length() < 3) { + // Apple reserves 2 character prefixes for themselves. They do use some + // 3 character prefixes, but they haven't updated the rules/docs. + std::cerr << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " Apple recommends they should be at least 3 characters long." + << std::endl; + std::cerr.flush(); + } + + // Check: Error/Warning - If the given package/prefix pair wasn't expected, + // issue a error/warning to added to the file. + if (have_expected_prefix_file) { + if (prefixes_must_be_registered) { + *out_error = y_absl::StrCat( + "error: '", file->name(), "' has 'option objc_class_prefix = \"", + prefix, "\";', but it is not registered. Add '", lookup_key, " = ", + (prefix.empty() ? "\"\"" : prefix), + "' to the expected prefixes file (", expected_prefixes_path, ")."); + return false; + } + + std::cerr + << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "'; consider adding '" + << lookup_key << " = " << (prefix.empty() ? "\"\"" : prefix) + << "' to the expected prefixes file (" << expected_prefixes_path << ")." + << std::endl; + std::cerr.flush(); + } + + return true; +} + +} // namespace + +Options::Options() { + // While there are generator options, also support env variables to help with + // build systems where it isn't as easy to hook in for add the generation + // options when invoking protoc. + const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); + if (file_path) { + expected_prefixes_path = file_path; + } + const char* suppressions = + getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS"); + if (suppressions) { + expected_prefixes_suppressions = + y_absl::StrSplit(suppressions, ';', y_absl::SkipEmpty()); + } + prefixes_must_be_registered = + BoolFromEnvVar("GPB_OBJC_PREFIXES_MUST_BE_REGISTERED", false); + require_prefixes = BoolFromEnvVar("GPB_OBJC_REQUIRE_PREFIXES", false); +} + +bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files, + TProtoStringType* out_error) { + // Options's ctor load from the environment. + Options options; + return ValidateObjCClassPrefixes(files, options, out_error); +} + +bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files, + const Options& validation_options, + TProtoStringType* out_error) { + // Allow a '-' as the path for the expected prefixes to completely disable + // even the most basic of checks. + if (validation_options.expected_prefixes_path == "-") { + return true; + } + + // Load the expected package prefixes, if available, to validate against. + y_absl::flat_hash_map<TProtoStringType, TProtoStringType> expected_package_prefixes; + if (!LoadExpectedPackagePrefixes(validation_options.expected_prefixes_path, + &expected_package_prefixes, out_error)) { + return false; + } + + for (auto file : files) { + bool should_skip = + (std::find(validation_options.expected_prefixes_suppressions.begin(), + validation_options.expected_prefixes_suppressions.end(), + file->name()) != + validation_options.expected_prefixes_suppressions.end()); + if (should_skip) { + continue; + } + + bool is_valid = + ValidateObjCClassPrefix(file, validation_options.expected_prefixes_path, + expected_package_prefixes, + validation_options.prefixes_must_be_registered, + validation_options.require_prefixes, out_error); + if (!is_valid) { + return false; + } + } + return true; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/names.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/names.h new file mode 100644 index 0000000000..3ee2cd8e90 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/names.h @@ -0,0 +1,179 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Helper functions for generating ObjectiveC code. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__ + +#include <string> +#include <vector> + +#include "google/protobuf/descriptor.h" + +// Must be included last +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// Get/Set the path to a file to load for objc class prefix lookups. +PROTOC_EXPORT y_absl::string_view GetPackageToPrefixMappingsPath(); +PROTOC_EXPORT void SetPackageToPrefixMappingsPath(y_absl::string_view file_path); +// Get/Set if the proto package should be used to make the default prefix for +// symbols. This will then impact most of the type naming apis below. It is done +// as a global to not break any other generator reusing the methods since they +// are exported. +PROTOC_EXPORT bool UseProtoPackageAsDefaultPrefix(); +PROTOC_EXPORT void SetUseProtoPackageAsDefaultPrefix(bool on_or_off); +// Get/Set the path to a file to load as exceptions when +// `UseProtoPackageAsDefaultPrefix()` is `true`. An empty string means there +// should be no exceptions. +PROTOC_EXPORT y_absl::string_view GetProtoPackagePrefixExceptionList(); +PROTOC_EXPORT void SetProtoPackagePrefixExceptionList( + y_absl::string_view file_path); +// Get/Set a prefix to add before the prefix generated from the package name. +// This is only used when UseProtoPackageAsDefaultPrefix() is True. +PROTOC_EXPORT y_absl::string_view GetForcedPackagePrefix(); +PROTOC_EXPORT void SetForcedPackagePrefix(y_absl::string_view prefix); + +// Returns true if the name requires a ns_returns_not_retained attribute applied +// to it. +PROTOC_EXPORT bool IsRetainedName(y_absl::string_view name); + +// Returns true if the name starts with "init" and will need to have special +// handling under ARC. +PROTOC_EXPORT bool IsInitName(y_absl::string_view name); + +// Returns true if the name requires a cf_returns_not_retained attribute applied +// to it. +PROTOC_EXPORT bool IsCreateName(y_absl::string_view name); + +// Gets the objc_class_prefix or the prefix made from the proto package. +PROTOC_EXPORT TProtoStringType FileClassPrefix(const FileDescriptor* file); + +// Gets the path of the file we're going to generate (sans the .pb.h +// extension). The path will be dependent on the objectivec package +// declared in the proto package. +PROTOC_EXPORT TProtoStringType FilePath(const FileDescriptor* file); + +// Just like FilePath(), but without the directory part. +PROTOC_EXPORT TProtoStringType FilePathBasename(const FileDescriptor* file); + +// Gets the name of the root class we'll generate in the file. This class +// is not meant for external consumption, but instead contains helpers that +// the rest of the classes need +PROTOC_EXPORT TProtoStringType FileClassName(const FileDescriptor* file); + +// These return the fully-qualified class name corresponding to the given +// descriptor. +PROTOC_EXPORT TProtoStringType ClassName(const Descriptor* descriptor); +PROTOC_EXPORT TProtoStringType ClassName(const Descriptor* descriptor, + TProtoStringType* out_suffix_added); +PROTOC_EXPORT TProtoStringType EnumName(const EnumDescriptor* descriptor); + +// Returns the fully-qualified name of the enum value corresponding to the +// the descriptor. +PROTOC_EXPORT TProtoStringType EnumValueName(const EnumValueDescriptor* descriptor); + +// Returns the name of the enum value corresponding to the descriptor. +PROTOC_EXPORT TProtoStringType EnumValueShortName( + const EnumValueDescriptor* descriptor); + +// Reverse what an enum does. +PROTOC_EXPORT TProtoStringType UnCamelCaseEnumShortName(y_absl::string_view name); + +// Returns the name to use for the extension (used as the method off the file's +// Root class). +PROTOC_EXPORT TProtoStringType ExtensionMethodName( + const FieldDescriptor* descriptor); + +// Returns the transformed field name. +PROTOC_EXPORT TProtoStringType FieldName(const FieldDescriptor* field); +PROTOC_EXPORT TProtoStringType FieldNameCapitalized(const FieldDescriptor* field); + +// Returns the transformed oneof name. +PROTOC_EXPORT TProtoStringType OneofEnumName(const OneofDescriptor* descriptor); +PROTOC_EXPORT TProtoStringType OneofName(const OneofDescriptor* descriptor); +PROTOC_EXPORT TProtoStringType OneofNameCapitalized( + const OneofDescriptor* descriptor); + +// Reverse of the above. +PROTOC_EXPORT TProtoStringType UnCamelCaseFieldName(y_absl::string_view name, + const FieldDescriptor* field); + +// The name the commonly used by the library when built as a framework. +// This lines up to the name used in the CocoaPod. +extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName; +// Returns the CPP symbol name to use as the gate for framework style imports +// for the given framework name to use. +PROTOC_EXPORT TProtoStringType ProtobufFrameworkImportSymbol( + y_absl::string_view framework_name); + +// --------------------------------------------------------------------------- + +// These aren't really "naming" related, but can be useful for something +// building on top of ObjC Protos to be able to share the knowledge/enforcement. + +// Checks if the file is one of the proto's bundled with the library. +PROTOC_EXPORT bool IsProtobufLibraryBundledProtoFile( + const FileDescriptor* file); + +// Generator Prefix Validation Options (see generator.cc for a +// description of each): +struct Options { + Options(); + TProtoStringType expected_prefixes_path; + std::vector<TProtoStringType> expected_prefixes_suppressions; + bool prefixes_must_be_registered; + bool require_prefixes; +}; + +// Checks the prefix for the given files and outputs any warnings as needed. If +// there are flat out errors, then out_error is filled in with the first error +// and the result is false. +PROTOC_EXPORT bool ValidateObjCClassPrefixes( + const std::vector<const FileDescriptor*>& files, + const Options& validation_options, TProtoStringType* out_error); +// Same was the other ValidateObjCClassPrefixes() calls, but the options all +// come from the environment variables. +PROTOC_EXPORT bool ValidateObjCClassPrefixes( + const std::vector<const FileDescriptor*>& files, TProtoStringType* out_error); + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/nsobject_methods.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/nsobject_methods.h new file mode 100644 index 0000000000..7a1b9ef2cd --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/nsobject_methods.h @@ -0,0 +1,227 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// NSObject methods +// Autogenerated by method_dump.sh. Do not edit by hand. +// Date: Thu Nov 1 14:12:16 PDT 2018 +// macOS: MacOSX10.14.sdk +// iOS: iPhoneSimulator12.1.sdk + +const char* const kNSObjectMethodsList[] = { + "CAMLType", + "CA_copyRenderValue", + "CA_prepareRenderValue", + "NS_copyCGImage", + "NS_tiledLayerVisibleRect", + "___tryRetain_OA", + "__autorelease_OA", + "__dealloc_zombie", + "__release_OA", + "__retain_OA", + "_accessibilityFinalize", + "_accessibilityIsTableViewDescendant", + "_accessibilityUIElementSpecifier", + "_accessibilityUseConvenienceAPI", + "_allowsDirectEncoding", + "_asScriptTerminologyNameArray", + "_asScriptTerminologyNameString", + "_bindingAdaptor", + "_cfTypeID", + "_copyDescription", + "_destroyObserverList", + "_didEndKeyValueObserving", + "_implicitObservationInfo", + "_internalAccessibilityAttributedHint", + "_internalAccessibilityAttributedLabel", + "_internalAccessibilityAttributedValue", + "_isAXConnector", + "_isAccessibilityContainerSectionCandidate", + "_isAccessibilityContentNavigatorSectionCandidate", + "_isAccessibilityContentSectionCandidate", + "_isAccessibilityTopLevelNavigatorSectionCandidate", + "_isDeallocating", + "_isKVOA", + "_isToManyChangeInformation", + "_ivarDescription", + "_localClassNameForClass", + "_methodDescription", + "_observerStorage", + "_overrideUseFastBlockObservers", + "_propertyDescription", + "_releaseBindingAdaptor", + "_scriptingCount", + "_scriptingCountNonrecursively", + "_scriptingDebugDescription", + "_scriptingExists", + "_scriptingShouldCheckObjectIndexes", + "_shortMethodDescription", + "_shouldSearchChildrenForSection", + "_traitStorageList", + "_tryRetain", + "_ui_descriptionBuilder", + "_uikit_variesByTraitCollections", + "_web_description", + "_webkit_invokeOnMainThread", + "_willBeginKeyValueObserving", + "accessibilityActivate", + "accessibilityActivationPoint", + "accessibilityAllowsOverriddenAttributesWhenIgnored", + "accessibilityAssistiveTechnologyFocusedIdentifiers", + "accessibilityAttributedHint", + "accessibilityAttributedLabel", + "accessibilityAttributedValue", + "accessibilityContainer", + "accessibilityContainerType", + "accessibilityCustomActions", + "accessibilityCustomRotors", + "accessibilityDecrement", + "accessibilityDragSourceDescriptors", + "accessibilityDropPointDescriptors", + "accessibilityElementCount", + "accessibilityElementDidBecomeFocused", + "accessibilityElementDidLoseFocus", + "accessibilityElementIsFocused", + "accessibilityElements", + "accessibilityElementsHidden", + "accessibilityFrame", + "accessibilityHeaderElements", + "accessibilityHint", + "accessibilityIdentification", + "accessibilityIdentifier", + "accessibilityIncrement", + "accessibilityLabel", + "accessibilityLanguage", + "accessibilityLocalizedStringKey", + "accessibilityNavigationStyle", + "accessibilityOverriddenAttributes", + "accessibilityParameterizedAttributeNames", + "accessibilityPath", + "accessibilityPerformEscape", + "accessibilityPerformMagicTap", + "accessibilityPresenterProcessIdentifier", + "accessibilityShouldUseUniqueId", + "accessibilitySupportsNotifications", + "accessibilitySupportsOverriddenAttributes", + "accessibilityTemporaryChildren", + "accessibilityTraits", + "accessibilityValue", + "accessibilityViewIsModal", + "accessibilityVisibleArea", + "allPropertyKeys", + "allowsWeakReference", + "attributeKeys", + "autoContentAccessingProxy", + "autorelease", + "awakeFromNib", + "boolValueSafe", + "bs_encoded", + "bs_isPlistableType", + "bs_secureEncoded", + "cl_json_serializeKey", + "class", + "classCode", + "classDescription", + "classForArchiver", + "classForCoder", + "classForKeyedArchiver", + "classForPortCoder", + "className", + "clearProperties", + "copy", + "dealloc", + "debugDescription", + "defaultAccessibilityTraits", + "description", + "doubleValueSafe", + "entityName", + "exposedBindings", + "finalize", + "finishObserving", + "flushKeyBindings", + "hash", + "init", + "int64ValueSafe", + "isAccessibilityElement", + "isAccessibilityElementByDefault", + "isElementAccessibilityExposedToInterfaceBuilder", + "isFault", + "isNSArray__", + "isNSCFConstantString__", + "isNSData__", + "isNSDate__", + "isNSDictionary__", + "isNSNumber__", + "isNSObject__", + "isNSOrderedSet__", + "isNSSet__", + "isNSString__", + "isNSTimeZone__", + "isNSValue__", + "isProxy", + "mutableCopy", + "nilValueForKey", + "objectSpecifier", + "observationInfo", + "pep_onDetachedThread", + "pep_onMainThread", + "pep_onMainThreadIfNecessary", + "prepareForInterfaceBuilder", + "release", + "releaseOnMainThread", + "retain", + "retainCount", + "retainWeakReference", + "scriptingProperties", + "self", + "shouldGroupAccessibilityChildren", + "storedAccessibilityActivationPoint", + "storedAccessibilityContainerType", + "storedAccessibilityElementsHidden", + "storedAccessibilityFrame", + "storedAccessibilityNavigationStyle", + "storedAccessibilityTraits", + "storedAccessibilityViewIsModal", + "storedIsAccessibilityElement", + "storedShouldGroupAccessibilityChildren", + "stringValueSafe", + "superclass", + "toManyRelationshipKeys", + "toOneRelationshipKeys", + "traitStorageList", + "un_safeBoolValue", + "userInterfaceItemIdentifier", + "utf8ValueSafe", + "valuesForKeysWithDictionary", + "zone", + // Protocol: CAAnimatableValue + // Protocol: CARenderValue + // Protocol: NSObject + // Protocol: ROCKRemoteInvocationInterface +}; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.cc deleted file mode 100644 index e1bb09f996..0000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ /dev/null @@ -1,681 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <google/protobuf/compiler/objectivec/objectivec_file.h> -#include <google/protobuf/compiler/objectivec/objectivec_enum.h> -#include <google/protobuf/compiler/objectivec/objectivec_extension.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/compiler/objectivec/objectivec_message.h> -#include <google/protobuf/compiler/code_generator.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/stubs/stl_util.h> -#include <google/protobuf/stubs/strutil.h> -#include <algorithm> // std::find() -#include <iostream> -#include <sstream> - -// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some -// error cases, so it seems to be ok to use as a back door for errors. - -namespace google { -namespace protobuf { -namespace compiler { -namespace objectivec { - -namespace { - -// This is also found in GPBBootstrap.h, and needs to be kept in sync. -const arc_i32 GOOGLE_PROTOBUF_OBJC_VERSION = 30004; - -const char* kHeaderExtension = ".pbobjc.h"; - -TProtoStringType BundledFileName(const FileDescriptor* file) { - return "GPB" + FilePathBasename(file) + kHeaderExtension; -} - -// Checks if a message contains any enums definitions (on the message or -// a nested message under it). -bool MessageContainsEnums(const Descriptor* message) { - if (message->enum_type_count() > 0) { - return true; - } - for (int i = 0; i < message->nested_type_count(); i++) { - if (MessageContainsEnums(message->nested_type(i))) { - return true; - } - } - return false; -} - -// Checks if a message contains any extension definitions (on the message or -// a nested message under it). -bool MessageContainsExtensions(const Descriptor* message) { - if (message->extension_count() > 0) { - return true; - } - for (int i = 0; i < message->nested_type_count(); i++) { - if (MessageContainsExtensions(message->nested_type(i))) { - return true; - } - } - return false; -} - -// Checks if the file contains any enum definitions (at the root or -// nested under a message). -bool FileContainsEnums(const FileDescriptor* file) { - if (file->enum_type_count() > 0) { - return true; - } - for (int i = 0; i < file->message_type_count(); i++) { - if (MessageContainsEnums(file->message_type(i))) { - return true; - } - } - return false; -} - -// Checks if the file contains any extensions definitions (at the root or -// nested under a message). -bool FileContainsExtensions(const FileDescriptor* file) { - if (file->extension_count() > 0) { - return true; - } - for (int i = 0; i < file->message_type_count(); i++) { - if (MessageContainsExtensions(file->message_type(i))) { - return true; - } - } - return false; -} - -bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) { - for (int i = 0; i < file->dependency_count(); i++) { - if (dep == file->dependency(i)) { - return true; - } - } - return false; -} - -struct FileDescriptorsOrderedByName { - inline bool operator()(const FileDescriptor* a, - const FileDescriptor* b) const { - return a->name() < b->name(); - } -}; - -} // namespace - -FileGenerator::CommonState::CommonState() { } - -const FileGenerator::CommonState::MinDepsEntry& -FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensionsInternal( - const FileDescriptor* file) { - auto it = deps_info_cache_.find(file); - if (it != deps_info_cache_.end()) { - return it->second; - } - - std::set<const FileDescriptor*> min_deps_collector; - std::set<const FileDescriptor*> covered_deps_collector; - std::set<const FileDescriptor*> to_prune; - for (int i = 0; i < file->dependency_count(); i++) { - const FileDescriptor* dep = file->dependency(i); - MinDepsEntry dep_info = - CollectMinimalFileDepsContainingExtensionsInternal(dep); - - // Everything the dep covered, this file will also cover. - covered_deps_collector.insert(dep_info.covered_deps.begin(), dep_info.covered_deps.end()); - // Prune everything from the dep's covered list in case another dep lists it - // as a min dep. - to_prune.insert(dep_info.covered_deps.begin(), dep_info.covered_deps.end()); - - // Does the dep have any extensions... - if (dep_info.has_extensions) { - // Yes -> Add this file, prune its min_deps and add them to the covered deps. - min_deps_collector.insert(dep); - to_prune.insert(dep_info.min_deps.begin(), dep_info.min_deps.end()); - covered_deps_collector.insert(dep_info.min_deps.begin(), dep_info.min_deps.end()); - } else { - // No -> Just use its min_deps. - min_deps_collector.insert(dep_info.min_deps.begin(), dep_info.min_deps.end()); - } - } - - const bool file_has_exts = FileContainsExtensions(file); - - // Fast path: if nothing to prune or there was only one dep, the prune work is - // a waste, skip it. - if (to_prune.empty() || file->dependency_count() == 1) { - return deps_info_cache_.insert( - {file, {file_has_exts, min_deps_collector, covered_deps_collector}}).first->second; - } - - std::set<const FileDescriptor*> min_deps; - std::copy_if(min_deps_collector.begin(), min_deps_collector.end(), - std::inserter(min_deps, min_deps.end()), - [&](const FileDescriptor* value){ - return to_prune.find(value) == to_prune.end(); - }); - return deps_info_cache_.insert( - {file, {file_has_exts, min_deps, covered_deps_collector}}).first->second; -} - -// Collect the deps of the given file that contain extensions. This can be used to -// create the chain of roots that need to be wired together. -// -// NOTE: If any changes are made to this and the supporting functions, you will -// need to manually validate what the generated code is for the test files: -// objectivec/Tests/unittest_extension_chain_*.proto -// There are comments about what the expected code should be line and limited -// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports -// specifically). -const std::vector<const FileDescriptor*> -FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensions( - const FileDescriptor* file) { - std::set<const FileDescriptor*> min_deps = - CollectMinimalFileDepsContainingExtensionsInternal(file).min_deps; - // Sort the list since pointer order isn't stable across runs. - std::vector<const FileDescriptor*> result(min_deps.begin(), min_deps.end()); - std::sort(result.begin(), result.end(), FileDescriptorsOrderedByName()); - return result; -} - -FileGenerator::FileGenerator(const FileDescriptor* file, - const GenerationOptions& generation_options, - CommonState& common_state) - : file_(file), - generation_options_(generation_options), - common_state_(common_state), - root_class_name_(FileClassName(file)), - is_bundled_proto_(IsProtobufLibraryBundledProtoFile(file)) { - for (int i = 0; i < file_->enum_type_count(); i++) { - EnumGenerator* generator = new EnumGenerator(file_->enum_type(i)); - enum_generators_.emplace_back(generator); - } - for (int i = 0; i < file_->message_type_count(); i++) { - MessageGenerator* generator = - new MessageGenerator(root_class_name_, file_->message_type(i)); - message_generators_.emplace_back(generator); - } - for (int i = 0; i < file_->extension_count(); i++) { - ExtensionGenerator* generator = - new ExtensionGenerator(root_class_name_, file_->extension(i)); - extension_generators_.emplace_back(generator); - } -} - -FileGenerator::~FileGenerator() {} - -void FileGenerator::GenerateHeader(io::Printer* printer) { - std::vector<TProtoStringType> headers; - // Generated files bundled with the library get minimal imports, everything - // else gets the wrapper so everything is usable. - if (is_bundled_proto_) { - headers.push_back("GPBDescriptor.h"); - headers.push_back("GPBMessage.h"); - headers.push_back("GPBRootObject.h"); - for (int i = 0; i < file_->dependency_count(); i++) { - const TProtoStringType header_name = BundledFileName(file_->dependency(i)); - headers.push_back(header_name); - } - } else { - headers.push_back("GPBProtocolBuffers.h"); - } - PrintFileRuntimePreamble(printer, headers); - - // Add some verification that the generated code matches the source the - // code is being compiled with. - // NOTE: This captures the raw numeric values at the time the generator was - // compiled, since that will be the versions for the ObjC runtime at that - // time. The constants in the generated code will then get their values at - // at compile time (so checking against the headers being used to compile). - printer->Print( - "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n" - "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n" - "#endif\n" - "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n" - "#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n" - "#endif\n" - "\n", - "google_protobuf_objc_version", StrCat(GOOGLE_PROTOBUF_OBJC_VERSION)); - - // The bundled protos (WKTs) don't use of forward declarations. - bool headers_use_forward_declarations = - generation_options_.headers_use_forward_declarations && !is_bundled_proto_; - - { - ImportWriter import_writer( - generation_options_.generate_for_named_framework, - generation_options_.named_framework_to_proto_path_mappings_path, - generation_options_.runtime_import_prefix, - /* include_wkt_imports = */ false); - const TProtoStringType header_extension(kHeaderExtension); - if (headers_use_forward_declarations) { - // #import any headers for "public imports" in the proto file. - for (int i = 0; i < file_->public_dependency_count(); i++) { - import_writer.AddFile(file_->public_dependency(i), header_extension); - } - } else { - for (int i = 0; i < file_->dependency_count(); i++) { - import_writer.AddFile(file_->dependency(i), header_extension); - } - } - import_writer.Print(printer); - } - - // Note: - // deprecated-declarations suppression is only needed if some place in this - // proto file is something deprecated or if it references something from - // another file that is deprecated. - printer->Print( - "// @@protoc_insertion_point(imports)\n" - "\n" - "#pragma clang diagnostic push\n" - "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" - "\n" - "CF_EXTERN_C_BEGIN\n" - "\n"); - - std::set<TProtoStringType> fwd_decls; - for (const auto& generator : message_generators_) { - generator->DetermineForwardDeclarations( - &fwd_decls, - /* include_external_types = */ headers_use_forward_declarations); - } - for (std::set<TProtoStringType>::const_iterator i(fwd_decls.begin()); - i != fwd_decls.end(); ++i) { - printer->Print("$value$;\n", "value", *i); - } - if (fwd_decls.begin() != fwd_decls.end()) { - printer->Print("\n"); - } - - printer->Print( - "NS_ASSUME_NONNULL_BEGIN\n" - "\n"); - - // need to write out all enums first - for (const auto& generator : enum_generators_) { - generator->GenerateHeader(printer); - } - - for (const auto& generator : message_generators_) { - generator->GenerateEnumHeader(printer); - } - - // For extensions to chain together, the Root gets created even if there - // are no extensions. - printer->Print( - "#pragma mark - $root_class_name$\n" - "\n" - "/**\n" - " * Exposes the extension registry for this file.\n" - " *\n" - " * The base class provides:\n" - " * @code\n" - " * + (GPBExtensionRegistry *)extensionRegistry;\n" - " * @endcode\n" - " * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n" - " * this file and all files that it depends on.\n" - " **/\n" - "GPB_FINAL @interface $root_class_name$ : GPBRootObject\n" - "@end\n" - "\n", - "root_class_name", root_class_name_); - - if (!extension_generators_.empty()) { - // The dynamic methods block is only needed if there are extensions. - printer->Print( - "@interface $root_class_name$ (DynamicMethods)\n", - "root_class_name", root_class_name_); - - for (const auto& generator : extension_generators_) { - generator->GenerateMembersHeader(printer); - } - - printer->Print("@end\n\n"); - } // !extension_generators_.empty() - - for (const auto& generator : message_generators_) { - generator->GenerateMessageHeader(printer); - } - - printer->Print( - "NS_ASSUME_NONNULL_END\n" - "\n" - "CF_EXTERN_C_END\n" - "\n" - "#pragma clang diagnostic pop\n" - "\n" - "// @@protoc_insertion_point(global_scope)\n"); -} - -void FileGenerator::GenerateSource(io::Printer* printer) { - // #import the runtime support. - std::vector<TProtoStringType> headers; - headers.push_back("GPBProtocolBuffers_RuntimeSupport.h"); - if (is_bundled_proto_) { - headers.push_back(BundledFileName(file_)); - } - PrintFileRuntimePreamble(printer, headers); - - // Enums use atomic in the generated code, so add the system import as needed. - if (FileContainsEnums(file_)) { - printer->Print( - "#import <stdatomic.h>\n" - "\n"); - } - - std::vector<const FileDescriptor*> deps_with_extensions = - common_state_.CollectMinimalFileDepsContainingExtensions(file_); - - // The bundled protos (WKTs) don't use of forward declarations. - bool headers_use_forward_declarations = - generation_options_.headers_use_forward_declarations && !is_bundled_proto_; - - { - ImportWriter import_writer( - generation_options_.generate_for_named_framework, - generation_options_.named_framework_to_proto_path_mappings_path, - generation_options_.runtime_import_prefix, - /* include_wkt_imports = */ false); - const TProtoStringType header_extension(kHeaderExtension); - - // #import the header for this proto file. - import_writer.AddFile(file_, header_extension); - - if (headers_use_forward_declarations) { - // #import the headers for anything that a plain dependency of this proto - // file (that means they were just an include, not a "public" include). - std::set<TProtoStringType> public_import_names; - for (int i = 0; i < file_->public_dependency_count(); i++) { - public_import_names.insert(file_->public_dependency(i)->name()); - } - for (int i = 0; i < file_->dependency_count(); i++) { - const FileDescriptor *dep = file_->dependency(i); - bool public_import = (public_import_names.count(dep->name()) != 0); - if (!public_import) { - import_writer.AddFile(dep, header_extension); - } - } - } - - // If any indirect dependency provided extensions, it needs to be directly - // imported so it can get merged into the root's extensions registry. - // See the Note by CollectMinimalFileDepsContainingExtensions before - // changing this. - for (std::vector<const FileDescriptor*>::iterator iter = - deps_with_extensions.begin(); - iter != deps_with_extensions.end(); ++iter) { - if (!IsDirectDependency(*iter, file_)) { - import_writer.AddFile(*iter, header_extension); - } - } - - import_writer.Print(printer); - } - - bool includes_oneof = false; - for (const auto& generator : message_generators_) { - if (generator->IncludesOneOfDefinition()) { - includes_oneof = true; - break; - } - } - - std::set<TProtoStringType> fwd_decls; - for (const auto& generator : message_generators_) { - generator->DetermineObjectiveCClassDefinitions(&fwd_decls); - } - for (const auto& generator : extension_generators_) { - generator->DetermineObjectiveCClassDefinitions(&fwd_decls); - } - - // Note: - // deprecated-declarations suppression is only needed if some place in this - // proto file is something deprecated or if it references something from - // another file that is deprecated. - // dollar-in-identifier-extension is needed because we use references to - // objc class names that have $ in identifiers. - printer->Print( - "// @@protoc_insertion_point(imports)\n" - "\n" - "#pragma clang diagnostic push\n" - "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"); - if (includes_oneof) { - // The generated code for oneof's uses direct ivar access, suppress the - // warning in case developer turn that on in the context they compile the - // generated code. - printer->Print( - "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n"); - } - if (!fwd_decls.empty()) { - printer->Print( - "#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n"); - } - printer->Print( - "\n"); - if (!fwd_decls.empty()) { - printer->Print( - "#pragma mark - Objective C Class declarations\n" - "// Forward declarations of Objective C classes that we can use as\n" - "// static values in struct initializers.\n" - "// We don't use [Foo class] because it is not a static value.\n"); - } - for (const auto& i : fwd_decls) { - printer->Print("$value$\n", "value", i); - } - if (!fwd_decls.empty()) { - printer->Print("\n"); - } - printer->Print( - "#pragma mark - $root_class_name$\n" - "\n" - "@implementation $root_class_name$\n\n", - "root_class_name", root_class_name_); - - const bool file_contains_extensions = FileContainsExtensions(file_); - - // If there were any extensions or this file has any dependencies, output - // a registry to override to create the file specific registry. - if (file_contains_extensions || !deps_with_extensions.empty()) { - printer->Print( - "+ (GPBExtensionRegistry*)extensionRegistry {\n" - " // This is called by +initialize so there is no need to worry\n" - " // about thread safety and initialization of registry.\n" - " static GPBExtensionRegistry* registry = nil;\n" - " if (!registry) {\n" - " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n" - " registry = [[GPBExtensionRegistry alloc] init];\n"); - - printer->Indent(); - printer->Indent(); - - if (file_contains_extensions) { - printer->Print( - "static GPBExtensionDescription descriptions[] = {\n"); - printer->Indent(); - for (const auto& generator : extension_generators_) { - generator->GenerateStaticVariablesInitialization(printer); - } - for (const auto& generator : message_generators_) { - generator->GenerateStaticVariablesInitialization(printer); - } - printer->Outdent(); - printer->Print( - "};\n" - "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n" - " GPBExtensionDescriptor *extension =\n" - " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]\n" - " usesClassRefs:YES];\n" - " [registry addExtension:extension];\n" - " [self globallyRegisterExtension:extension];\n" - " [extension release];\n" - "}\n"); - } - - if (deps_with_extensions.empty()) { - printer->Print( - "// None of the imports (direct or indirect) defined extensions, so no need to add\n" - "// them to this registry.\n"); - } else { - printer->Print( - "// Merge in the imports (direct or indirect) that defined extensions.\n"); - for (std::vector<const FileDescriptor*>::iterator iter = - deps_with_extensions.begin(); - iter != deps_with_extensions.end(); ++iter) { - const TProtoStringType root_class_name(FileClassName((*iter))); - printer->Print( - "[registry addExtensions:[$dependency$ extensionRegistry]];\n", - "dependency", root_class_name); - } - } - - printer->Outdent(); - printer->Outdent(); - - printer->Print( - " }\n" - " return registry;\n" - "}\n"); - } else { - if (file_->dependency_count() > 0) { - printer->Print( - "// No extensions in the file and none of the imports (direct or indirect)\n" - "// defined extensions, so no need to generate +extensionRegistry.\n"); - } else { - printer->Print( - "// No extensions in the file and no imports, so no need to generate\n" - "// +extensionRegistry.\n"); - } - } - - printer->Print("\n@end\n\n"); - - // File descriptor only needed if there are messages to use it. - if (!message_generators_.empty()) { - std::map<TProtoStringType, TProtoStringType> vars; - vars["root_class_name"] = root_class_name_; - vars["package"] = file_->package(); - vars["objc_prefix"] = FileClassPrefix(file_); - switch (file_->syntax()) { - case FileDescriptor::SYNTAX_UNKNOWN: - vars["syntax"] = "GPBFileSyntaxUnknown"; - break; - case FileDescriptor::SYNTAX_PROTO2: - vars["syntax"] = "GPBFileSyntaxProto2"; - break; - case FileDescriptor::SYNTAX_PROTO3: - vars["syntax"] = "GPBFileSyntaxProto3"; - break; - } - printer->Print(vars, - "#pragma mark - $root_class_name$_FileDescriptor\n" - "\n" - "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n" - " // This is called by +initialize so there is no need to worry\n" - " // about thread safety of the singleton.\n" - " static GPBFileDescriptor *descriptor = NULL;\n" - " if (!descriptor) {\n" - " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"); - if (!vars["objc_prefix"].empty()) { - printer->Print( - vars, - " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" - " objcPrefix:@\"$objc_prefix$\"\n" - " syntax:$syntax$];\n"); - } else { - printer->Print( - vars, - " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" - " syntax:$syntax$];\n"); - } - printer->Print( - " }\n" - " return descriptor;\n" - "}\n" - "\n"); - } - - for (const auto& generator : enum_generators_) { - generator->GenerateSource(printer); - } - for (const auto& generator : message_generators_) { - generator->GenerateSource(printer); - } - - printer->Print( - "\n" - "#pragma clang diagnostic pop\n" - "\n" - "// @@protoc_insertion_point(global_scope)\n"); -} - -// Helper to print the import of the runtime support at the top of generated -// files. This currently only supports the runtime coming from a framework -// as defined by the official CocoaPod. -void FileGenerator::PrintFileRuntimePreamble( - io::Printer* printer, - const std::vector<TProtoStringType>& headers_to_import) const { - printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n", - "filename", file_->name()); - - if (is_bundled_proto_) { - // This is basically a clone of ImportWriter::PrintRuntimeImports() but - // without the CPP symbol gate, since within the bundled files, that isn't - // needed. - TProtoStringType import_prefix = generation_options_.runtime_import_prefix; - if (!import_prefix.empty()) { - import_prefix += "/"; - } - for (const auto& header : headers_to_import) { - printer->Print( - "#import \"$import_prefix$$header$\"\n", - "import_prefix", import_prefix, - "header", header); - } - } else { - ImportWriter::PrintRuntimeImports( - printer, headers_to_import, generation_options_.runtime_import_prefix, true); - } - - printer->Print("\n"); -} - -} // namespace objectivec -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc deleted file mode 100644 index 5122fa46c0..0000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ /dev/null @@ -1,2044 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef _MSC_VER -#include <unistd.h> -#endif -#include <climits> -#include <errno.h> -#include <fcntl.h> -#include <fstream> -#include <iostream> -#include <sstream> -#include <stdlib.h> -#include <unordered_set> -#include <vector> - -#include <google/protobuf/compiler/code_generator.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/io/io_win32.h> -#include <google/protobuf/port.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/port.h> -#include <google/protobuf/stubs/strutil.h> - -// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some -// error cases, so it seems to be ok to use as a back door for errors. - -namespace google { -namespace protobuf { -namespace compiler { -namespace objectivec { - -// <io.h> is transitively included in this file. Import the functions explicitly -// in this port namespace to avoid ambiguous definition. -namespace posix { -#ifdef _WIN32 -using ::google::protobuf::io::win32::open; -#else -using ::open; -#endif -} // namespace port - -namespace { - -bool BoolFromEnvVar(const char* env_var, bool default_value) { - const char* value = getenv(env_var); - if (value) { - return TProtoStringType("YES") == ToUpper(value); - } - return default_value; -} - -class SimpleLineCollector : public LineConsumer { - public: - SimpleLineCollector(std::unordered_set<TProtoStringType>* inout_set) - : set_(inout_set) {} - - virtual bool ConsumeLine(const StringPiece& line, TProtoStringType* out_error) override { - set_->insert(TProtoStringType(line)); - return true; - } - - private: - std::unordered_set<TProtoStringType>* set_; -}; - -class PackageToPrefixesCollector : public LineConsumer { - public: - PackageToPrefixesCollector(const TProtoStringType &usage, - std::map<TProtoStringType, TProtoStringType>* inout_package_to_prefix_map) - : usage_(usage), prefix_map_(inout_package_to_prefix_map) {} - - virtual bool ConsumeLine(const StringPiece& line, TProtoStringType* out_error) override; - - private: - const TProtoStringType usage_; - std::map<TProtoStringType, TProtoStringType>* prefix_map_; -}; - -class PrefixModeStorage { - public: - PrefixModeStorage(); - - const TProtoStringType package_to_prefix_mappings_path() const { return package_to_prefix_mappings_path_; } - void set_package_to_prefix_mappings_path(const TProtoStringType& path) { - package_to_prefix_mappings_path_ = path; - package_to_prefix_map_.clear(); - } - - TProtoStringType prefix_from_proto_package_mappings(const FileDescriptor* file); - - bool use_package_name() const { return use_package_name_; } - void set_use_package_name(bool on_or_off) { use_package_name_ = on_or_off; } - - const TProtoStringType exception_path() const { return exception_path_; } - void set_exception_path(const TProtoStringType& path) { - exception_path_ = path; - exceptions_.clear(); - } - - bool is_package_exempted(const TProtoStringType& package); - - // When using a proto package as the prefix, this should be added as the - // prefix in front of it. - const TProtoStringType& forced_package_prefix() const { return forced_prefix_; } - - private: - bool use_package_name_; - std::map<TProtoStringType, TProtoStringType> package_to_prefix_map_; - TProtoStringType package_to_prefix_mappings_path_; - TProtoStringType exception_path_; - TProtoStringType forced_prefix_; - std::unordered_set<TProtoStringType> exceptions_; -}; - -PrefixModeStorage::PrefixModeStorage() { - // Even thought there are generation options, have an env back door since some - // of these helpers could be used in other plugins. - - use_package_name_ = BoolFromEnvVar("GPB_OBJC_USE_PACKAGE_AS_PREFIX", false); - - const char* exception_path = getenv("GPB_OBJC_PACKAGE_PREFIX_EXCEPTIONS_PATH"); - if (exception_path) { - exception_path_ = exception_path; - } - - // This one is a not expected to be common, so it doesn't get a generation - // option, just the env var. - const char* prefix = getenv("GPB_OBJC_USE_PACKAGE_AS_PREFIX_PREFIX"); - if (prefix) { - forced_prefix_ = prefix; - } -} - -TProtoStringType PrefixModeStorage::prefix_from_proto_package_mappings(const FileDescriptor* file) { - if (!file) { - return ""; - } - - if (package_to_prefix_map_.empty() && !package_to_prefix_mappings_path_.empty()) { - TProtoStringType error_str; - // Re use the same collector as we use for expected_prefixes_path since the file - // format is the same. - PackageToPrefixesCollector collector("Package to prefixes", &package_to_prefix_map_); - if (!ParseSimpleFile(package_to_prefix_mappings_path_, &collector, &error_str)) { - if (error_str.empty()) { - error_str = TProtoStringType("protoc:0: warning: Failed to parse") - + TProtoStringType(" prefix to proto package mappings file: ") - + package_to_prefix_mappings_path_; - } - std::cerr << error_str << std::endl; - std::cerr.flush(); - package_to_prefix_map_.clear(); - } - } - - const TProtoStringType package = file->package(); - // For files without packages, the can be registered as "no_package:PATH", - // allowing the expected prefixes file. - static const TProtoStringType no_package_prefix("no_package:"); - const TProtoStringType lookup_key = package.empty() ? no_package_prefix + file->name() : package; - - std::map<TProtoStringType, TProtoStringType>::const_iterator prefix_lookup = - package_to_prefix_map_.find(lookup_key); - - if (prefix_lookup != package_to_prefix_map_.end()) { - return prefix_lookup->second; - } - - return ""; -} - -bool PrefixModeStorage::is_package_exempted(const TProtoStringType& package) { - if (exceptions_.empty() && !exception_path_.empty()) { - TProtoStringType error_str; - SimpleLineCollector collector(&exceptions_); - if (!ParseSimpleFile(exception_path_, &collector, &error_str)) { - if (error_str.empty()) { - error_str = TProtoStringType("protoc:0: warning: Failed to parse") - + TProtoStringType(" package prefix exceptions file: ") - + exception_path_; - } - std::cerr << error_str << std::endl; - std::cerr.flush(); - exceptions_.clear(); - } - - // If the file was empty put something in it so it doesn't get reloaded over - // and over. - if (exceptions_.empty()) { - exceptions_.insert("<not a real package>"); - } - } - - return exceptions_.count(package) != 0; -} - -PrefixModeStorage g_prefix_mode; - -} // namespace - -TProtoStringType GetPackageToPrefixMappingsPath() { - return g_prefix_mode.package_to_prefix_mappings_path(); -} - -void SetPackageToPrefixMappingsPath(const TProtoStringType& file_path) { - g_prefix_mode.set_package_to_prefix_mappings_path(file_path); -} - -bool UseProtoPackageAsDefaultPrefix() { - return g_prefix_mode.use_package_name(); -} - -void SetUseProtoPackageAsDefaultPrefix(bool on_or_off) { - g_prefix_mode.set_use_package_name(on_or_off); -} - -TProtoStringType GetProtoPackagePrefixExceptionList() { - return g_prefix_mode.exception_path(); -} - -void SetProtoPackagePrefixExceptionList(const TProtoStringType& file_path) { - g_prefix_mode.set_exception_path(file_path); -} - -Options::Options() { - // While there are generator options, also support env variables to help with - // build systems where it isn't as easy to hook in for add the generation - // options when invoking protoc. - const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); - if (file_path) { - expected_prefixes_path = file_path; - } - const char* suppressions = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS"); - if (suppressions) { - expected_prefixes_suppressions = - Split(suppressions, ";", true); - } - prefixes_must_be_registered = - BoolFromEnvVar("GPB_OBJC_PREFIXES_MUST_BE_REGISTERED", false); - require_prefixes = BoolFromEnvVar("GPB_OBJC_REQUIRE_PREFIXES", false); -} - -namespace { - -std::unordered_set<TProtoStringType> MakeWordsMap(const char* const words[], - size_t num_words) { - std::unordered_set<TProtoStringType> result; - for (int i = 0; i < num_words; i++) { - result.insert(words[i]); - } - return result; -} - -const char* const kUpperSegmentsList[] = {"url", "http", "https"}; - -std::unordered_set<TProtoStringType> kUpperSegments = - MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList)); - -bool ascii_isnewline(char c) { - return c == '\n' || c == '\r'; -} - -// Internal helper for name handing. -// Do not expose this outside of helpers, stick to having functions for specific -// cases (ClassName(), FieldName()), so there is always consistent suffix rules. -TProtoStringType UnderscoresToCamelCase(const TProtoStringType& input, - bool first_capitalized) { - std::vector<TProtoStringType> values; - TProtoStringType current; - - bool last_char_was_number = false; - bool last_char_was_lower = false; - bool last_char_was_upper = false; - for (int i = 0; i < input.size(); i++) { - char c = input[i]; - if (ascii_isdigit(c)) { - if (!last_char_was_number) { - values.push_back(current); - current = ""; - } - current += c; - last_char_was_number = last_char_was_lower = last_char_was_upper = false; - last_char_was_number = true; - } else if (ascii_islower(c)) { - // lowercase letter can follow a lowercase or uppercase letter - if (!last_char_was_lower && !last_char_was_upper) { - values.push_back(current); - current = ""; - } - current += c; // already lower - last_char_was_number = last_char_was_lower = last_char_was_upper = false; - last_char_was_lower = true; - } else if (ascii_isupper(c)) { - if (!last_char_was_upper) { - values.push_back(current); - current = ""; - } - current += ascii_tolower(c); - last_char_was_number = last_char_was_lower = last_char_was_upper = false; - last_char_was_upper = true; - } else { - last_char_was_number = last_char_was_lower = last_char_was_upper = false; - } - } - values.push_back(current); - - TProtoStringType result; - bool first_segment_forces_upper = false; - for (std::vector<TProtoStringType>::iterator i = values.begin(); i != values.end(); - ++i) { - TProtoStringType value = *i; - bool all_upper = (kUpperSegments.count(value) > 0); - if (all_upper && (result.length() == 0)) { - first_segment_forces_upper = true; - } - for (int j = 0; j < value.length(); j++) { - if (j == 0 || all_upper) { - value[j] = ascii_toupper(value[j]); - } else { - // Nothing, already in lower. - } - } - result += value; - } - if ((result.length() != 0) && - !first_capitalized && - !first_segment_forces_upper) { - result[0] = ascii_tolower(result[0]); - } - return result; -} - -const char* const kReservedWordList[] = { - // Note NSObject Methods: - // These are brought in from objectivec_nsobject_methods.h that is generated - // using method_dump.sh. See kNSObjectMethods below. - - // Objective C "keywords" that aren't in C - // From - // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c - // with some others added on. - "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway", - "self", "instancetype", "nullable", "nonnull", "nil", "Nil", - "YES", "NO", "weak", - - // C/C++ keywords (Incl C++ 0x11) - // From http://en.cppreference.com/w/cpp/keywords - "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor", - "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", - "compl", "const", "constexpr", "const_cast", "continue", "decltype", - "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit", - "export", "extern ", "false", "float", "for", "friend", "goto", "if", - "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", - "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", - "public", "register", "reinterpret_cast", "return", "short", "signed", - "sizeof", "static", "static_assert", "static_cast", "struct", "switch", - "template", "this", "thread_local", "throw", "true", "try", "typedef", - "typeid", "typename", "union", "unsigned", "using", "virtual", "void", - "volatile", "wchar_t", "while", "xor", "xor_eq", - - // C99 keywords - // From - // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm - "restrict", - - // GCC/Clang extension - "typeof", - - // Not a keyword, but will break you - "NULL", - - // C88+ specs call for these to be macros, so depending on what they are - // defined to be it can lead to odd errors for some Xcode/SDK versions. - "stdin", "stdout", "stderr", - - // Objective-C Runtime typedefs - // From <obc/runtime.h> - "Category", "Ivar", "Method", "Protocol", - - // GPBMessage Methods - // Only need to add instance methods that may conflict with - // method declared in protos. The main cases are methods - // that take no arguments, or setFoo:/hasFoo: type methods. - "clear", "data", "delimitedData", "descriptor", "extensionRegistry", - "extensionsCurrentlySet", "initialized", "isInitialized", "serializedSize", - "sortedExtensionsInUse", "unknownFields", - - // MacTypes.h names - "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount", - "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount", - "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType", - "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style", - "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord", -}; - -// returns true is input starts with __ or _[A-Z] which are reserved identifiers -// in C/ C++. All calls should go through UnderscoresToCamelCase before getting here -// but this verifies and allows for future expansion if we decide to redefine what a -// reserved C identifier is (for example the GNU list -// https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html ) -bool IsReservedCIdentifier(const TProtoStringType& input) { - if (input.length() > 2) { - if (input.at(0) == '_') { - if (isupper(input.at(1)) || input.at(1) == '_') { - return true; - } - } - } - return false; -} - -TProtoStringType SanitizeNameForObjC(const TProtoStringType& prefix, - const TProtoStringType& input, - const TProtoStringType& extension, - TProtoStringType* out_suffix_added) { - static const std::unordered_set<TProtoStringType> kReservedWords = - MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList)); - static const std::unordered_set<TProtoStringType> kNSObjectMethods = - MakeWordsMap(kNSObjectMethodsList, GOOGLE_ARRAYSIZE(kNSObjectMethodsList)); - TProtoStringType sanitized; - // We add the prefix in the cases where the string is missing a prefix. - // We define "missing a prefix" as where 'input': - // a) Doesn't start with the prefix or - // b) Isn't equivalent to the prefix or - // c) Has the prefix, but the letter after the prefix is lowercase - if (HasPrefixString(input, prefix)) { - if (input.length() == prefix.length() || !ascii_isupper(input[prefix.length()])) { - sanitized = prefix + input; - } else { - sanitized = input; - } - } else { - sanitized = prefix + input; - } - if (IsReservedCIdentifier(sanitized) || - (kReservedWords.count(sanitized) > 0) || - (kNSObjectMethods.count(sanitized) > 0)) { - if (out_suffix_added) *out_suffix_added = extension; - return sanitized + extension; - } - if (out_suffix_added) out_suffix_added->clear(); - return sanitized; -} - -TProtoStringType NameFromFieldDescriptor(const FieldDescriptor* field) { - if (field->type() == FieldDescriptor::TYPE_GROUP) { - return field->message_type()->name(); - } else { - return field->name(); - } -} - -void PathSplit(const TProtoStringType& path, TProtoStringType* directory, - TProtoStringType* basename) { - TProtoStringType::size_type last_slash = path.rfind('/'); - if (last_slash == TProtoStringType::npos) { - if (directory) { - *directory = ""; - } - if (basename) { - *basename = path; - } - } else { - if (directory) { - *directory = path.substr(0, last_slash); - } - if (basename) { - *basename = path.substr(last_slash + 1); - } - } -} - -bool IsSpecialName(const TProtoStringType& name, const TProtoStringType* special_names, - size_t count) { - for (size_t i = 0; i < count; ++i) { - size_t length = special_names[i].length(); - if (name.compare(0, length, special_names[i]) == 0) { - if (name.length() > length) { - // If name is longer than the retained_name[i] that it matches - // the next character must be not lower case (newton vs newTon vs - // new_ton). - return !ascii_islower(name[length]); - } else { - return true; - } - } - } - return false; -} - -TProtoStringType GetZeroEnumNameForFlagType(const FlagType flag_type) { - switch(flag_type) { - case FLAGTYPE_DESCRIPTOR_INITIALIZATION: - return "GPBDescriptorInitializationFlag_None"; - case FLAGTYPE_EXTENSION: - return "GPBExtensionNone"; - case FLAGTYPE_FIELD: - return "GPBFieldNone"; - default: - GOOGLE_LOG(FATAL) << "Can't get here."; - return "0"; - } -} - -TProtoStringType GetEnumNameForFlagType(const FlagType flag_type) { - switch(flag_type) { - case FLAGTYPE_DESCRIPTOR_INITIALIZATION: - return "GPBDescriptorInitializationFlags"; - case FLAGTYPE_EXTENSION: - return "GPBExtensionOptions"; - case FLAGTYPE_FIELD: - return "GPBFieldFlags"; - default: - GOOGLE_LOG(FATAL) << "Can't get here."; - return TProtoStringType(); - } -} - -void MaybeUnQuote(StringPiece* input) { - if ((input->length() >= 2) && - ((*input->data() == '\'' || *input->data() == '"')) && - ((*input)[input->length() - 1] == *input->data())) { - input->remove_prefix(1); - input->remove_suffix(1); - } -} - -} // namespace - -// Escape C++ trigraphs by escaping question marks to \? -TProtoStringType EscapeTrigraphs(const TProtoStringType& to_escape) { - return StringReplace(to_escape, "?", "\\?", true); -} - -void TrimWhitespace(StringPiece* input) { - while (!input->empty() && ascii_isspace(*input->data())) { - input->remove_prefix(1); - } - while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) { - input->remove_suffix(1); - } -} - -bool IsRetainedName(const TProtoStringType& name) { - // List of prefixes from - // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html - static const TProtoStringType retained_names[] = {"new", "alloc", "copy", - "mutableCopy"}; - return IsSpecialName(name, retained_names, - sizeof(retained_names) / sizeof(retained_names[0])); -} - -bool IsInitName(const TProtoStringType& name) { - static const TProtoStringType init_names[] = {"init"}; - return IsSpecialName(name, init_names, - sizeof(init_names) / sizeof(init_names[0])); -} - -TProtoStringType BaseFileName(const FileDescriptor* file) { - TProtoStringType basename; - PathSplit(file->name(), NULL, &basename); - return basename; -} - -TProtoStringType FileClassPrefix(const FileDescriptor* file) { - // Always honor the file option. - if (file->options().has_objc_class_prefix()) { - return file->options().objc_class_prefix(); - } - - // If package prefix is specified in an prefix to proto mappings file then use that. - TProtoStringType objc_class_prefix = g_prefix_mode.prefix_from_proto_package_mappings(file); - if (!objc_class_prefix.empty()) { - return objc_class_prefix; - } - - // If package prefix isn't enabled, done. - if (!g_prefix_mode.use_package_name()) { - return ""; - } - - // If the package is in the exceptions list, done. - if (g_prefix_mode.is_package_exempted(file->package())) { - return ""; - } - - // Transform the package into a prefix: use the dot segments as part, - // camelcase each one and then join them with underscores, and add an - // underscore at the end. - TProtoStringType result; - const std::vector<TProtoStringType> segments = Split(file->package(), ".", true); - for (const auto& segment : segments) { - const TProtoStringType part = UnderscoresToCamelCase(segment, true); - if (part.empty()) { - continue; - } - if (!result.empty()) { - result.append("_"); - } - result.append(part); - } - if (!result.empty()) { - result.append("_"); - } - return g_prefix_mode.forced_package_prefix() + result; -} - -TProtoStringType FilePath(const FileDescriptor* file) { - TProtoStringType output; - TProtoStringType basename; - TProtoStringType directory; - PathSplit(file->name(), &directory, &basename); - if (directory.length() > 0) { - output = directory + "/"; - } - basename = StripProto(basename); - - // CamelCase to be more ObjC friendly. - basename = UnderscoresToCamelCase(basename, true); - - output += basename; - return output; -} - -TProtoStringType FilePathBasename(const FileDescriptor* file) { - TProtoStringType output; - TProtoStringType basename; - TProtoStringType directory; - PathSplit(file->name(), &directory, &basename); - basename = StripProto(basename); - - // CamelCase to be more ObjC friendly. - output = UnderscoresToCamelCase(basename, true); - - return output; -} - -TProtoStringType FileClassName(const FileDescriptor* file) { - const TProtoStringType prefix = FileClassPrefix(file); - const TProtoStringType name = - UnderscoresToCamelCase(StripProto(BaseFileName(file)), true) + "Root"; - // There aren't really any reserved words that end in "Root", but playing - // it safe and checking. - return SanitizeNameForObjC(prefix, name, "_RootClass", NULL); -} - -TProtoStringType ClassNameWorker(const Descriptor* descriptor) { - TProtoStringType name; - if (descriptor->containing_type() != NULL) { - name = ClassNameWorker(descriptor->containing_type()); - name += "_"; - } - return name + descriptor->name(); -} - -TProtoStringType ClassNameWorker(const EnumDescriptor* descriptor) { - TProtoStringType name; - if (descriptor->containing_type() != NULL) { - name = ClassNameWorker(descriptor->containing_type()); - name += "_"; - } - return name + descriptor->name(); -} - -TProtoStringType ClassName(const Descriptor* descriptor) { - return ClassName(descriptor, NULL); -} - -TProtoStringType ClassName(const Descriptor* descriptor, - TProtoStringType* out_suffix_added) { - // 1. Message names are used as is (style calls for CamelCase, trust it). - // 2. Check for reserved word at the very end and then suffix things. - const TProtoStringType prefix = FileClassPrefix(descriptor->file()); - const TProtoStringType name = ClassNameWorker(descriptor); - return SanitizeNameForObjC(prefix, name, "_Class", out_suffix_added); -} - -TProtoStringType EnumName(const EnumDescriptor* descriptor) { - // 1. Enum names are used as is (style calls for CamelCase, trust it). - // 2. Check for reserved word at the every end and then suffix things. - // message Fixed { - // message Size {...} - // enum Mumble {...} - // ... - // } - // yields Fixed_Class, Fixed_Size. - const TProtoStringType prefix = FileClassPrefix(descriptor->file()); - const TProtoStringType name = ClassNameWorker(descriptor); - return SanitizeNameForObjC(prefix, name, "_Enum", NULL); -} - -TProtoStringType EnumValueName(const EnumValueDescriptor* descriptor) { - // Because of the Switch enum compatibility, the name on the enum has to have - // the suffix handing, so it slightly diverges from how nested classes work. - // enum Fixed { - // FOO = 1 - // } - // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo). - const TProtoStringType class_name = EnumName(descriptor->type()); - const TProtoStringType value_str = - UnderscoresToCamelCase(descriptor->name(), true); - const TProtoStringType name = class_name + "_" + value_str; - // There aren't really any reserved words with an underscore and a leading - // capital letter, but playing it safe and checking. - return SanitizeNameForObjC("", name, "_Value", NULL); -} - -TProtoStringType EnumValueShortName(const EnumValueDescriptor* descriptor) { - // Enum value names (EnumValueName above) are the enum name turned into - // a class name and then the value name is CamelCased and concatenated; the - // whole thing then gets sanitized for reserved words. - // The "short name" is intended to be the final leaf, the value name; but - // you can't simply send that off to sanitize as that could result in it - // getting modified when the full name didn't. For example enum - // "StorageModes" has a value "retain". So the full name is - // "StorageModes_Retain", but if we sanitize "retain" it would become - // "RetainValue". - // So the right way to get the short name is to take the full enum name - // and then strip off the enum name (leaving the value name and anything - // done by sanitize). - const TProtoStringType class_name = EnumName(descriptor->type()); - const TProtoStringType long_name_prefix = class_name + "_"; - const TProtoStringType long_name = EnumValueName(descriptor); - return StripPrefixString(long_name, long_name_prefix); -} - -TProtoStringType UnCamelCaseEnumShortName(const TProtoStringType& name) { - TProtoStringType result; - for (int i = 0; i < name.size(); i++) { - char c = name[i]; - if (i > 0 && ascii_isupper(c)) { - result += '_'; - } - result += ascii_toupper(c); - } - return result; -} - -TProtoStringType ExtensionMethodName(const FieldDescriptor* descriptor) { - const TProtoStringType name = NameFromFieldDescriptor(descriptor); - const TProtoStringType result = UnderscoresToCamelCase(name, false); - return SanitizeNameForObjC("", result, "_Extension", NULL); -} - -TProtoStringType FieldName(const FieldDescriptor* field) { - const TProtoStringType name = NameFromFieldDescriptor(field); - TProtoStringType result = UnderscoresToCamelCase(name, false); - if (field->is_repeated() && !field->is_map()) { - // Add "Array" before do check for reserved worlds. - result += "Array"; - } else { - // If it wasn't repeated, but ends in "Array", force on the _p suffix. - if (HasSuffixString(result, "Array")) { - result += "_p"; - } - } - return SanitizeNameForObjC("", result, "_p", NULL); -} - -TProtoStringType FieldNameCapitalized(const FieldDescriptor* field) { - // Want the same suffix handling, so upcase the first letter of the other - // name. - TProtoStringType result = FieldName(field); - if (result.length() > 0) { - result[0] = ascii_toupper(result[0]); - } - return result; -} - -TProtoStringType OneofEnumName(const OneofDescriptor* descriptor) { - const Descriptor* fieldDescriptor = descriptor->containing_type(); - TProtoStringType name = ClassName(fieldDescriptor); - name += "_" + UnderscoresToCamelCase(descriptor->name(), true) + "_OneOfCase"; - // No sanitize needed because the OS never has names that end in _OneOfCase. - return name; -} - -TProtoStringType OneofName(const OneofDescriptor* descriptor) { - TProtoStringType name = UnderscoresToCamelCase(descriptor->name(), false); - // No sanitize needed because it gets OneOfCase added and that shouldn't - // ever conflict. - return name; -} - -TProtoStringType OneofNameCapitalized(const OneofDescriptor* descriptor) { - // Use the common handling and then up-case the first letter. - TProtoStringType result = OneofName(descriptor); - if (result.length() > 0) { - result[0] = ascii_toupper(result[0]); - } - return result; -} - -TProtoStringType ObjCClass(const TProtoStringType& class_name) { - return TProtoStringType("GPBObjCClass(") + class_name + ")"; -} - -TProtoStringType ObjCClassDeclaration(const TProtoStringType& class_name) { - return TProtoStringType("GPBObjCClassDeclaration(") + class_name + ");"; -} - -TProtoStringType UnCamelCaseFieldName(const TProtoStringType& name, const FieldDescriptor* field) { - TProtoStringType worker(name); - if (HasSuffixString(worker, "_p")) { - worker = StripSuffixString(worker, "_p"); - } - if (field->is_repeated() && HasSuffixString(worker, "Array")) { - worker = StripSuffixString(worker, "Array"); - } - if (field->type() == FieldDescriptor::TYPE_GROUP) { - if (worker.length() > 0) { - if (ascii_islower(worker[0])) { - worker[0] = ascii_toupper(worker[0]); - } - } - return worker; - } else { - TProtoStringType result; - for (int i = 0; i < worker.size(); i++) { - char c = worker[i]; - if (ascii_isupper(c)) { - if (i > 0) { - result += '_'; - } - result += ascii_tolower(c); - } else { - result += c; - } - } - return result; - } -} - -TProtoStringType GetCapitalizedType(const FieldDescriptor* field) { - switch (field->type()) { - case FieldDescriptor::TYPE_INT32: - return "Int32"; - case FieldDescriptor::TYPE_UINT32: - return "UInt32"; - case FieldDescriptor::TYPE_SINT32: - return "SInt32"; - case FieldDescriptor::TYPE_FIXED32: - return "Fixed32"; - case FieldDescriptor::TYPE_SFIXED32: - return "SFixed32"; - case FieldDescriptor::TYPE_INT64: - return "Int64"; - case FieldDescriptor::TYPE_UINT64: - return "UInt64"; - case FieldDescriptor::TYPE_SINT64: - return "SInt64"; - case FieldDescriptor::TYPE_FIXED64: - return "Fixed64"; - case FieldDescriptor::TYPE_SFIXED64: - return "SFixed64"; - case FieldDescriptor::TYPE_FLOAT: - return "Float"; - case FieldDescriptor::TYPE_DOUBLE: - return "Double"; - case FieldDescriptor::TYPE_BOOL: - return "Bool"; - case FieldDescriptor::TYPE_STRING: - return "String"; - case FieldDescriptor::TYPE_BYTES: - return "Bytes"; - case FieldDescriptor::TYPE_ENUM: - return "Enum"; - case FieldDescriptor::TYPE_GROUP: - return "Group"; - case FieldDescriptor::TYPE_MESSAGE: - return "Message"; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return TProtoStringType(); -} - -ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) { - switch (field_type) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SFIXED32: - return OBJECTIVECTYPE_INT32; - - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_FIXED32: - return OBJECTIVECTYPE_UINT32; - - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_SFIXED64: - return OBJECTIVECTYPE_INT64; - - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_FIXED64: - return OBJECTIVECTYPE_UINT64; - - case FieldDescriptor::TYPE_FLOAT: - return OBJECTIVECTYPE_FLOAT; - - case FieldDescriptor::TYPE_DOUBLE: - return OBJECTIVECTYPE_DOUBLE; - - case FieldDescriptor::TYPE_BOOL: - return OBJECTIVECTYPE_BOOLEAN; - - case FieldDescriptor::TYPE_STRING: - return OBJECTIVECTYPE_STRING; - - case FieldDescriptor::TYPE_BYTES: - return OBJECTIVECTYPE_DATA; - - case FieldDescriptor::TYPE_ENUM: - return OBJECTIVECTYPE_ENUM; - - case FieldDescriptor::TYPE_GROUP: - case FieldDescriptor::TYPE_MESSAGE: - return OBJECTIVECTYPE_MESSAGE; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return OBJECTIVECTYPE_INT32; -} - -bool IsPrimitiveType(const FieldDescriptor* field) { - ObjectiveCType type = GetObjectiveCType(field); - switch (type) { - case OBJECTIVECTYPE_INT32: - case OBJECTIVECTYPE_UINT32: - case OBJECTIVECTYPE_INT64: - case OBJECTIVECTYPE_UINT64: - case OBJECTIVECTYPE_FLOAT: - case OBJECTIVECTYPE_DOUBLE: - case OBJECTIVECTYPE_BOOLEAN: - case OBJECTIVECTYPE_ENUM: - return true; - break; - default: - return false; - } -} - -bool IsReferenceType(const FieldDescriptor* field) { - return !IsPrimitiveType(field); -} - -static TProtoStringType HandleExtremeFloatingPoint(TProtoStringType val, - bool add_float_suffix) { - if (val == "nan") { - return "NAN"; - } else if (val == "inf") { - return "INFINITY"; - } else if (val == "-inf") { - return "-INFINITY"; - } else { - // float strings with ., e or E need to have f appended - if (add_float_suffix && (val.find(".") != TProtoStringType::npos || - val.find("e") != TProtoStringType::npos || - val.find("E") != TProtoStringType::npos)) { - val += "f"; - } - return val; - } -} - -TProtoStringType GPBGenericValueFieldName(const FieldDescriptor* field) { - // Returns the field within the GPBGenericValue union to use for the given - // field. - if (field->is_repeated()) { - return "valueMessage"; - } - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return "valueInt32"; - case FieldDescriptor::CPPTYPE_UINT32: - return "valueUInt32"; - case FieldDescriptor::CPPTYPE_INT64: - return "valueInt64"; - case FieldDescriptor::CPPTYPE_UINT64: - return "valueUInt64"; - case FieldDescriptor::CPPTYPE_FLOAT: - return "valueFloat"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return "valueDouble"; - case FieldDescriptor::CPPTYPE_BOOL: - return "valueBool"; - case FieldDescriptor::CPPTYPE_STRING: - if (field->type() == FieldDescriptor::TYPE_BYTES) { - return "valueData"; - } else { - return "valueString"; - } - case FieldDescriptor::CPPTYPE_ENUM: - return "valueEnum"; - case FieldDescriptor::CPPTYPE_MESSAGE: - return "valueMessage"; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return TProtoStringType(); -} - - -TProtoStringType DefaultValue(const FieldDescriptor* field) { - // Repeated fields don't have defaults. - if (field->is_repeated()) { - return "nil"; - } - - // Switch on cpp_type since we need to know which default_value_* method - // of FieldDescriptor to call. - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - // gcc and llvm reject the decimal form of kint32min and kint64min. - if (field->default_value_int32() == INT_MIN) { - return "-0x80000000"; - } - return StrCat(field->default_value_int32()); - case FieldDescriptor::CPPTYPE_UINT32: - return StrCat(field->default_value_uint32()) + "U"; - case FieldDescriptor::CPPTYPE_INT64: - // gcc and llvm reject the decimal form of kint32min and kint64min. - if (field->default_value_int64() == LLONG_MIN) { - return "-0x8000000000000000LL"; - } - return StrCat(field->default_value_int64()) + "LL"; - case FieldDescriptor::CPPTYPE_UINT64: - return StrCat(field->default_value_uint64()) + "ULL"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return HandleExtremeFloatingPoint( - SimpleDtoa(field->default_value_double()), false); - case FieldDescriptor::CPPTYPE_FLOAT: - return HandleExtremeFloatingPoint( - SimpleFtoa(field->default_value_float()), true); - case FieldDescriptor::CPPTYPE_BOOL: - return field->default_value_bool() ? "YES" : "NO"; - case FieldDescriptor::CPPTYPE_STRING: { - const bool has_default_value = field->has_default_value(); - const TProtoStringType& default_string = field->default_value_string(); - if (!has_default_value || default_string.length() == 0) { - // If the field is defined as being the empty string, - // then we will just assign to nil, as the empty string is the - // default for both strings and data. - return "nil"; - } - if (field->type() == FieldDescriptor::TYPE_BYTES) { - // We want constant fields in our data structures so we can - // declare them as static. To achieve this we cheat and stuff - // a escaped c string (prefixed with a length) into the data - // field, and cast it to an (NSData*) so it will compile. - // The runtime library knows how to handle it. - - // Must convert to a standard byte order for packing length into - // a cstring. - arc_ui32 length = ghtonl(default_string.length()); - TProtoStringType bytes((const char*)&length, sizeof(length)); - bytes.append(default_string); - return "(NSData*)\"" + EscapeTrigraphs(CEscape(bytes)) + "\""; - } else { - return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\""; - } - } - case FieldDescriptor::CPPTYPE_ENUM: - return EnumValueName(field->default_value_enum()); - case FieldDescriptor::CPPTYPE_MESSAGE: - return "nil"; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return TProtoStringType(); -} - -bool HasNonZeroDefaultValue(const FieldDescriptor* field) { - // Repeated fields don't have defaults. - if (field->is_repeated()) { - return false; - } - - // As much as checking field->has_default_value() seems useful, it isn't - // because of enums. proto2 syntax allows the first item in an enum (the - // default) to be non zero. So checking field->has_default_value() would - // result in missing this non zero default. See MessageWithOneBasedEnum in - // objectivec/Tests/unittest_objc.proto for a test Message to confirm this. - - // Some proto file set the default to the zero value, so make sure the value - // isn't the zero case. - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return field->default_value_int32() != 0; - case FieldDescriptor::CPPTYPE_UINT32: - return field->default_value_uint32() != 0U; - case FieldDescriptor::CPPTYPE_INT64: - return field->default_value_int64() != 0LL; - case FieldDescriptor::CPPTYPE_UINT64: - return field->default_value_uint64() != 0ULL; - case FieldDescriptor::CPPTYPE_DOUBLE: - return field->default_value_double() != 0.0; - case FieldDescriptor::CPPTYPE_FLOAT: - return field->default_value_float() != 0.0f; - case FieldDescriptor::CPPTYPE_BOOL: - return field->default_value_bool(); - case FieldDescriptor::CPPTYPE_STRING: { - const TProtoStringType& default_string = field->default_value_string(); - return default_string.length() != 0; - } - case FieldDescriptor::CPPTYPE_ENUM: - return field->default_value_enum()->number() != 0; - case FieldDescriptor::CPPTYPE_MESSAGE: - return false; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return false; -} - -TProtoStringType BuildFlagsString(const FlagType flag_type, - const std::vector<TProtoStringType>& strings) { - if (strings.empty()) { - return GetZeroEnumNameForFlagType(flag_type); - } else if (strings.size() == 1) { - return strings[0]; - } - TProtoStringType string("(" + GetEnumNameForFlagType(flag_type) + ")("); - for (size_t i = 0; i != strings.size(); ++i) { - if (i > 0) { - string.append(" | "); - } - string.append(strings[i]); - } - string.append(")"); - return string; -} - -TProtoStringType BuildCommentsString(const SourceLocation& location, - bool prefer_single_line) { - const TProtoStringType& comments = location.leading_comments.empty() - ? location.trailing_comments - : location.leading_comments; - std::vector<TProtoStringType> lines; - lines = Split(comments, "\n", false); - while (!lines.empty() && lines.back().empty()) { - lines.pop_back(); - } - // If there are no comments, just return an empty string. - if (lines.empty()) { - return ""; - } - - TProtoStringType prefix; - TProtoStringType suffix; - TProtoStringType final_comments; - TProtoStringType epilogue; - - bool add_leading_space = false; - - if (prefer_single_line && lines.size() == 1) { - prefix = "/** "; - suffix = " */\n"; - } else { - prefix = "* "; - suffix = "\n"; - final_comments += "/**\n"; - epilogue = " **/\n"; - add_leading_space = true; - } - - for (int i = 0; i < lines.size(); i++) { - TProtoStringType line = StripPrefixString(lines[i], " "); - // HeaderDoc and appledoc use '\' and '@' for markers; escape them. - line = StringReplace(line, "\\", "\\\\", true); - line = StringReplace(line, "@", "\\@", true); - // Decouple / from * to not have inline comments inside comments. - line = StringReplace(line, "/*", "/\\*", true); - line = StringReplace(line, "*/", "*\\/", true); - line = prefix + line; - StripWhitespace(&line); - // If not a one line, need to add the first space before *, as - // StripWhitespace would have removed it. - line = (add_leading_space ? " " : "") + line; - final_comments += line + suffix; - } - final_comments += epilogue; - return final_comments; -} - -// Making these a generator option for folks that don't use CocoaPods, but do -// want to put the library in a framework is an interesting question. The -// problem is it means changing sources shipped with the library to actually -// use a different value; so it isn't as simple as a option. -const char* const ProtobufLibraryFrameworkName = "Protobuf"; - -TProtoStringType ProtobufFrameworkImportSymbol(const TProtoStringType& framework_name) { - // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS - TProtoStringType result = TProtoStringType("GPB_USE_"); - result += ToUpper(framework_name); - result += "_FRAMEWORK_IMPORTS"; - return result; -} - -bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) { - // We don't check the name prefix or proto package because some files - // (descriptor.proto), aren't shipped generated by the library, so this - // seems to be the safest way to only catch the ones shipped. - const TProtoStringType name = file->name(); - if (name == "google/protobuf/any.proto" || - name == "google/protobuf/api.proto" || - name == "google/protobuf/duration.proto" || - name == "google/protobuf/empty.proto" || - name == "google/protobuf/field_mask.proto" || - name == "google/protobuf/source_context.proto" || - name == "google/protobuf/struct.proto" || - name == "google/protobuf/timestamp.proto" || - name == "google/protobuf/type.proto" || - name == "google/protobuf/wrappers.proto") { - return true; - } - return false; -} - -bool ReadLine(StringPiece* input, StringPiece* line) { - for (int len = 0; len < input->size(); ++len) { - if (ascii_isnewline((*input)[len])) { - *line = StringPiece(input->data(), len); - ++len; // advance over the newline - *input = StringPiece(input->data() + len, input->size() - len); - return true; - } - } - return false; // Ran out of input with no newline. -} - -void RemoveComment(StringPiece* input) { - int offset = input->find('#'); - if (offset != StringPiece::npos) { - input->remove_suffix(input->length() - offset); - } -} - -namespace { - -bool PackageToPrefixesCollector::ConsumeLine( - const StringPiece& line, TProtoStringType* out_error) { - int offset = line.find('='); - if (offset == StringPiece::npos) { - *out_error = usage_ + " file line without equal sign: '" + StrCat(line) + "'."; - return false; - } - StringPiece package = line.substr(0, offset); - StringPiece prefix = line.substr(offset + 1); - TrimWhitespace(&package); - TrimWhitespace(&prefix); - MaybeUnQuote(&prefix); - // Don't really worry about error checking the package/prefix for - // being valid. Assume the file is validated when it is created/edited. - (*prefix_map_)[TProtoStringType(package)] = TProtoStringType(prefix); - return true; -} - -bool LoadExpectedPackagePrefixes(const TProtoStringType& expected_prefixes_path, - std::map<TProtoStringType, TProtoStringType>* prefix_map, - TProtoStringType* out_error) { - if (expected_prefixes_path.empty()) { - return true; - } - - PackageToPrefixesCollector collector("Expected prefixes", prefix_map); - return ParseSimpleFile( - expected_prefixes_path, &collector, out_error); -} - -bool ValidateObjCClassPrefix( - const FileDescriptor* file, const TProtoStringType& expected_prefixes_path, - const std::map<TProtoStringType, TProtoStringType>& expected_package_prefixes, - bool prefixes_must_be_registered, bool require_prefixes, - TProtoStringType* out_error) { - // Reminder: An explicit prefix option of "" is valid in case the default - // prefixing is set to use the proto package and a file needs to be generated - // without any prefix at all (for legacy reasons). - - bool has_prefix = file->options().has_objc_class_prefix(); - bool have_expected_prefix_file = !expected_prefixes_path.empty(); - - const TProtoStringType prefix = file->options().objc_class_prefix(); - const TProtoStringType package = file->package(); - // For files without packages, the can be registered as "no_package:PATH", - // allowing the expected prefixes file. - static const TProtoStringType no_package_prefix("no_package:"); - const TProtoStringType lookup_key = - package.empty() ? no_package_prefix + file->name() : package; - - // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some - // error cases, so it seems to be ok to use as a back door for warnings. - - // Check: Error - See if there was an expected prefix for the package and - // report if it doesn't match (wrong or missing). - std::map<TProtoStringType, TProtoStringType>::const_iterator package_match = - expected_package_prefixes.find(lookup_key); - if (package_match != expected_package_prefixes.end()) { - // There was an entry, and... - if (has_prefix && package_match->second == prefix) { - // ...it matches. All good, out of here! - return true; - } else { - // ...it didn't match! - *out_error = "error: Expected 'option objc_class_prefix = \"" + - package_match->second + "\";'"; - if (!package.empty()) { - *out_error += " for package '" + package + "'"; - } - *out_error += " in '" + file->name() + "'"; - if (has_prefix) { - *out_error += "; but found '" + prefix + "' instead"; - } - *out_error += "."; - return false; - } - } - - // If there was no prefix option, we're done at this point. - if (!has_prefix) { - if (require_prefixes) { - *out_error = - "error: '" + file->name() + "' does not have a required 'option" + - " objc_class_prefix'."; - return false; - } - return true; - } - - // When the prefix is non empty, check it against the expected entries. - if (!prefix.empty() && have_expected_prefix_file) { - // For a non empty prefix, look for any other package that uses the prefix. - TProtoStringType other_package_for_prefix; - for (std::map<TProtoStringType, TProtoStringType>::const_iterator i = - expected_package_prefixes.begin(); - i != expected_package_prefixes.end(); ++i) { - if (i->second == prefix) { - other_package_for_prefix = i->first; - // Stop on the first real package listing, if it was a no_package file - // specific entry, keep looking to try and find a package one. - if (!HasPrefixString(other_package_for_prefix, no_package_prefix)) { - break; - } - } - } - - // Check: Error - Make sure the prefix wasn't expected for a different - // package (overlap is allowed, but it has to be listed as an expected - // overlap). - if (!other_package_for_prefix.empty()) { - *out_error = - "error: Found 'option objc_class_prefix = \"" + prefix + - "\";' in '" + file->name() + "'; that prefix is already used for "; - if (HasPrefixString(other_package_for_prefix, no_package_prefix)) { - *out_error += "file '" + - StripPrefixString(other_package_for_prefix, no_package_prefix) + - "'."; - } else { - *out_error += "'package " + other_package_for_prefix + ";'."; - } - *out_error += - " It can only be reused by adding '" + lookup_key + " = " + prefix + - "' to the expected prefixes file (" + expected_prefixes_path + ")."; - return false; // Only report first usage of the prefix. - } - } // !prefix.empty() && have_expected_prefix_file - - // Check: Warning - Make sure the prefix is is a reasonable value according - // to Apple's rules (the checks above implicitly whitelist anything that - // doesn't meet these rules). - if (!prefix.empty() && !ascii_isupper(prefix[0])) { - std::cerr - << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" - << prefix << "\";' in '" << file->name() << "';" - << " it should start with a capital letter." << std::endl; - std::cerr.flush(); - } - if (!prefix.empty() && prefix.length() < 3) { - // Apple reserves 2 character prefixes for themselves. They do use some - // 3 character prefixes, but they haven't updated the rules/docs. - std::cerr - << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" - << prefix << "\";' in '" << file->name() << "';" - << " Apple recommends they should be at least 3 characters long." - << std::endl; - std::cerr.flush(); - } - - // Check: Error/Warning - If the given package/prefix pair wasn't expected, - // issue a error/warning to added to the file. - if (have_expected_prefix_file) { - if (prefixes_must_be_registered) { - *out_error = - "error: '" + file->name() + "' has 'option objc_class_prefix = \"" + - prefix + "\";', but it is not registered. Add '" + lookup_key + " = " + - (prefix.empty() ? "\"\"" : prefix) + - "' to the expected prefixes file (" + expected_prefixes_path + ")."; - return false; - } - - std::cerr - << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" - << prefix << "\";' in '" << file->name() << "'; consider adding '" - << lookup_key << " = " << (prefix.empty() ? "\"\"" : prefix) - << "' to the expected prefixes file (" << expected_prefixes_path - << ")." << std::endl; - std::cerr.flush(); - } - - return true; -} - -} // namespace - -bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files, - TProtoStringType* out_error) { - // Options's ctor load from the environment. - Options options; - return ValidateObjCClassPrefixes(files, options, out_error); -} - -bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files, - const Options& generation_options, - TProtoStringType* out_error) { - // Allow a '-' as the path for the expected prefixes to completely disable - // even the most basic of checks. - if (generation_options.expected_prefixes_path == "-") { - return true; - } - - // Load the expected package prefixes, if available, to validate against. - std::map<TProtoStringType, TProtoStringType> expected_package_prefixes; - if (!LoadExpectedPackagePrefixes(generation_options.expected_prefixes_path, - &expected_package_prefixes, - out_error)) { - return false; - } - - for (int i = 0; i < files.size(); i++) { - bool should_skip = - (std::find(generation_options.expected_prefixes_suppressions.begin(), - generation_options.expected_prefixes_suppressions.end(), - files[i]->name()) - != generation_options.expected_prefixes_suppressions.end()); - if (should_skip) { - continue; - } - - bool is_valid = - ValidateObjCClassPrefix(files[i], - generation_options.expected_prefixes_path, - expected_package_prefixes, - generation_options.prefixes_must_be_registered, - generation_options.require_prefixes, - out_error); - if (!is_valid) { - return false; - } - } - return true; -} - -TextFormatDecodeData::TextFormatDecodeData() { } - -TextFormatDecodeData::~TextFormatDecodeData() { } - -void TextFormatDecodeData::AddString(arc_i32 key, - const TProtoStringType& input_for_decode, - const TProtoStringType& desired_output) { - for (std::vector<DataEntry>::const_iterator i = entries_.begin(); - i != entries_.end(); ++i) { - if (i->first == key) { - std::cerr << "error: duplicate key (" << key - << ") making TextFormat data, input: \"" << input_for_decode - << "\", desired: \"" << desired_output << "\"." << std::endl; - std::cerr.flush(); - abort(); - } - } - - const TProtoStringType& data = TextFormatDecodeData::DecodeDataForString( - input_for_decode, desired_output); - entries_.push_back(DataEntry(key, data)); -} - -TProtoStringType TextFormatDecodeData::Data() const { - std::ostringstream data_stringstream; - - if (num_entries() > 0) { - io::OstreamOutputStream data_outputstream(&data_stringstream); - io::CodedOutputStream output_stream(&data_outputstream); - - output_stream.WriteVarint32(num_entries()); - for (std::vector<DataEntry>::const_iterator i = entries_.begin(); - i != entries_.end(); ++i) { - output_stream.WriteVarint32(i->first); - output_stream.WriteString(i->second); - } - } - - data_stringstream.flush(); - return TProtoStringType{data_stringstream.str()}; -} - -namespace { - -// Helper to build up the decode data for a string. -class DecodeDataBuilder { - public: - DecodeDataBuilder() { Reset(); } - - bool AddCharacter(const char desired, const char input); - void AddUnderscore() { - Push(); - need_underscore_ = true; - } - TProtoStringType Finish() { - Push(); - return decode_data_; - } - - private: - static constexpr uint8_t kAddUnderscore = 0x80; - - static constexpr uint8_t kOpAsIs = 0x00; - static constexpr uint8_t kOpFirstUpper = 0x40; - static constexpr uint8_t kOpFirstLower = 0x20; - static constexpr uint8_t kOpAllUpper = 0x60; - - static constexpr int kMaxSegmentLen = 0x1f; - - void AddChar(const char desired) { - ++segment_len_; - is_all_upper_ &= ascii_isupper(desired); - } - - void Push() { - uint8_t op = (op_ | segment_len_); - if (need_underscore_) op |= kAddUnderscore; - if (op != 0) { - decode_data_ += (char)op; - } - Reset(); - } - - bool AddFirst(const char desired, const char input) { - if (desired == input) { - op_ = kOpAsIs; - } else if (desired == ascii_toupper(input)) { - op_ = kOpFirstUpper; - } else if (desired == ascii_tolower(input)) { - op_ = kOpFirstLower; - } else { - // Can't be transformed to match. - return false; - } - AddChar(desired); - return true; - } - - void Reset() { - need_underscore_ = false; - op_ = 0; - segment_len_ = 0; - is_all_upper_ = true; - } - - bool need_underscore_; - bool is_all_upper_; - uint8_t op_; - int segment_len_; - - TProtoStringType decode_data_; -}; - -bool DecodeDataBuilder::AddCharacter(const char desired, const char input) { - // If we've hit the max size, push to start a new segment. - if (segment_len_ == kMaxSegmentLen) { - Push(); - } - if (segment_len_ == 0) { - return AddFirst(desired, input); - } - - // Desired and input match... - if (desired == input) { - // If we aren't transforming it, or we're upper casing it and it is - // supposed to be uppercase; just add it to the segment. - if ((op_ != kOpAllUpper) || ascii_isupper(desired)) { - AddChar(desired); - return true; - } - - // Add the current segment, and start the next one. - Push(); - return AddFirst(desired, input); - } - - // If we need to uppercase, and everything so far has been uppercase, - // promote op to AllUpper. - if ((desired == ascii_toupper(input)) && is_all_upper_) { - op_ = kOpAllUpper; - AddChar(desired); - return true; - } - - // Give up, push and start a new segment. - Push(); - return AddFirst(desired, input); -} - -// If decode data can't be generated, a directive for the raw string -// is used instead. -TProtoStringType DirectDecodeString(const TProtoStringType& str) { - TProtoStringType result; - result += (char)'\0'; // Marker for full string. - result += str; - result += (char)'\0'; // End of string. - return result; -} - -} // namespace - -// static -TProtoStringType TextFormatDecodeData::DecodeDataForString( - const TProtoStringType& input_for_decode, const TProtoStringType& desired_output) { - if (input_for_decode.empty() || desired_output.empty()) { - std::cerr << "error: got empty string for making TextFormat data, input: \"" - << input_for_decode << "\", desired: \"" << desired_output << "\"." - << std::endl; - std::cerr.flush(); - abort(); - } - if ((input_for_decode.find('\0') != TProtoStringType::npos) || - (desired_output.find('\0') != TProtoStringType::npos)) { - std::cerr << "error: got a null char in a string for making TextFormat data," - << " input: \"" << CEscape(input_for_decode) << "\", desired: \"" - << CEscape(desired_output) << "\"." << std::endl; - std::cerr.flush(); - abort(); - } - - DecodeDataBuilder builder; - - // Walk the output building it from the input. - int x = 0; - for (int y = 0; y < desired_output.size(); y++) { - const char d = desired_output[y]; - if (d == '_') { - builder.AddUnderscore(); - continue; - } - - if (x >= input_for_decode.size()) { - // Out of input, no way to encode it, just return a full decode. - return DirectDecodeString(desired_output); - } - if (builder.AddCharacter(d, input_for_decode[x])) { - ++x; // Consumed one input - } else { - // Couldn't transform for the next character, just return a full decode. - return DirectDecodeString(desired_output); - } - } - - if (x != input_for_decode.size()) { - // Extra input (suffix from name sanitizing?), just return a full decode. - return DirectDecodeString(desired_output); - } - - // Add the end marker. - return builder.Finish() + (char)'\0'; -} - -namespace { - -class Parser { - public: - Parser(LineConsumer* line_consumer) - : line_consumer_(line_consumer), line_(0) {} - - // Feeds in some input, parse what it can, returning success/failure. Calling - // again after an error is undefined. - bool ParseChunk(StringPiece chunk, TProtoStringType* out_error); - - // Should be called to finish parsing (after all input has been provided via - // successful calls to ParseChunk(), calling after a ParseChunk() failure is - // undefined). Returns success/failure. - bool Finish(TProtoStringType* out_error); - - int last_line() const { return line_; } - - private: - LineConsumer* line_consumer_; - int line_; - TProtoStringType leftover_; -}; - -bool Parser::ParseChunk(StringPiece chunk, TProtoStringType* out_error) { - StringPiece full_chunk; - if (!leftover_.empty()) { - leftover_ += TProtoStringType(chunk); - full_chunk = StringPiece(leftover_); - } else { - full_chunk = chunk; - } - - StringPiece line; - while (ReadLine(&full_chunk, &line)) { - ++line_; - RemoveComment(&line); - TrimWhitespace(&line); - if (!line.empty() && !line_consumer_->ConsumeLine(line, out_error)) { - if (out_error->empty()) { - *out_error = "ConsumeLine failed without setting an error."; - } - leftover_.clear(); - return false; - } - } - - if (full_chunk.empty()) { - leftover_.clear(); - } else { - leftover_ = TProtoStringType(full_chunk); - } - return true; -} - -bool Parser::Finish(TProtoStringType* out_error) { - // If there is still something to go, flush it with a newline. - if (!leftover_.empty() && !ParseChunk("\n", out_error)) { - return false; - } - // This really should never fail if ParseChunk succeeded, but check to be sure. - if (!leftover_.empty()) { - *out_error = "ParseSimple Internal error: finished with pending data."; - return false; - } - return true; -} - -TProtoStringType FullErrorString(const TProtoStringType& name, int line_num, const TProtoStringType& msg) { - return TProtoStringType("error: ") + name + " Line " + StrCat(line_num) + ", " + msg; -} - -} // namespace - -LineConsumer::LineConsumer() {} - -LineConsumer::~LineConsumer() {} - -bool ParseSimpleFile(const TProtoStringType& path, LineConsumer* line_consumer, - TProtoStringType* out_error) { - int fd; - do { - fd = posix::open(path.c_str(), O_RDONLY); - } while (fd < 0 && errno == EINTR); - if (fd < 0) { - *out_error = TProtoStringType("error: Unable to open \"") + path + "\", " + - strerror(errno); - return false; - } - io::FileInputStream file_stream(fd); - file_stream.SetCloseOnDelete(true); - - return ParseSimpleStream(file_stream, path, line_consumer, out_error); -} - -bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream, - const TProtoStringType& stream_name, - LineConsumer* line_consumer, - TProtoStringType* out_error) { - TProtoStringType local_error; - Parser parser(line_consumer); - const void* buf; - int buf_len; - while (input_stream.Next(&buf, &buf_len)) { - if (buf_len == 0) { - continue; - } - - if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len), - &local_error)) { - *out_error = FullErrorString(stream_name, parser.last_line(), local_error); - return false; - } - } - if (!parser.Finish(&local_error)) { - *out_error = FullErrorString(stream_name, parser.last_line(), local_error); - return false; - } - return true; -} - -ImportWriter::ImportWriter( - const TProtoStringType& generate_for_named_framework, - const TProtoStringType& named_framework_to_proto_path_mappings_path, - const TProtoStringType& runtime_import_prefix, bool include_wkt_imports) - : generate_for_named_framework_(generate_for_named_framework), - named_framework_to_proto_path_mappings_path_( - named_framework_to_proto_path_mappings_path), - runtime_import_prefix_(runtime_import_prefix), - include_wkt_imports_(include_wkt_imports), - need_to_parse_mapping_file_(true) {} - -ImportWriter::~ImportWriter() {} - -void ImportWriter::AddFile(const FileDescriptor* file, - const TProtoStringType& header_extension) { - if (IsProtobufLibraryBundledProtoFile(file)) { - // The imports of the WKTs are only needed within the library itself, - // in other cases, they get skipped because the generated code already - // import GPBProtocolBuffers.h and hence proves them. - if (include_wkt_imports_) { - const TProtoStringType header_name = - "GPB" + FilePathBasename(file) + header_extension; - protobuf_imports_.push_back(header_name); - } - return; - } - - // Lazy parse any mappings. - if (need_to_parse_mapping_file_) { - ParseFrameworkMappings(); - } - - std::map<TProtoStringType, TProtoStringType>::iterator proto_lookup = - proto_file_to_framework_name_.find(file->name()); - if (proto_lookup != proto_file_to_framework_name_.end()) { - other_framework_imports_.push_back( - proto_lookup->second + "/" + - FilePathBasename(file) + header_extension); - return; - } - - if (!generate_for_named_framework_.empty()) { - other_framework_imports_.push_back( - generate_for_named_framework_ + "/" + - FilePathBasename(file) + header_extension); - return; - } - - other_imports_.push_back(FilePath(file) + header_extension); -} - -void ImportWriter::Print(io::Printer* printer) const { - bool add_blank_line = false; - - if (!protobuf_imports_.empty()) { - PrintRuntimeImports(printer, protobuf_imports_, runtime_import_prefix_); - add_blank_line = true; - } - - if (!other_framework_imports_.empty()) { - if (add_blank_line) { - printer->Print("\n"); - } - - for (std::vector<TProtoStringType>::const_iterator iter = - other_framework_imports_.begin(); - iter != other_framework_imports_.end(); ++iter) { - printer->Print( - "#import <$header$>\n", - "header", *iter); - } - - add_blank_line = true; - } - - if (!other_imports_.empty()) { - if (add_blank_line) { - printer->Print("\n"); - } - - for (std::vector<TProtoStringType>::const_iterator iter = other_imports_.begin(); - iter != other_imports_.end(); ++iter) { - printer->Print( - "#import \"$header$\"\n", - "header", *iter); - } - } -} - -void ImportWriter::PrintRuntimeImports( - io::Printer* printer, const std::vector<TProtoStringType>& header_to_import, - const TProtoStringType& runtime_import_prefix, bool default_cpp_symbol) { - // Given an override, use that. - if (!runtime_import_prefix.empty()) { - for (const auto& header : header_to_import) { - printer->Print( - " #import \"$import_prefix$/$header$\"\n", - "import_prefix", runtime_import_prefix, - "header", header); - } - return; - } - - const TProtoStringType framework_name(ProtobufLibraryFrameworkName); - const TProtoStringType cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); - - if (default_cpp_symbol) { - printer->Print( - "// This CPP symbol can be defined to use imports that match up to the framework\n" - "// imports needed when using CocoaPods.\n" - "#if !defined($cpp_symbol$)\n" - " #define $cpp_symbol$ 0\n" - "#endif\n" - "\n", - "cpp_symbol", cpp_symbol); - } - - printer->Print( - "#if $cpp_symbol$\n", - "cpp_symbol", cpp_symbol); - for (const auto& header : header_to_import) { - printer->Print( - " #import <$framework_name$/$header$>\n", - "framework_name", framework_name, - "header", header); - } - printer->Print( - "#else\n"); - for (const auto& header : header_to_import) { - printer->Print( - " #import \"$header$\"\n", - "header", header); - } - printer->Print( - "#endif\n"); -} - -void ImportWriter::ParseFrameworkMappings() { - need_to_parse_mapping_file_ = false; - if (named_framework_to_proto_path_mappings_path_.empty()) { - return; // Nothing to do. - } - - ProtoFrameworkCollector collector(&proto_file_to_framework_name_); - TProtoStringType parse_error; - if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_, - &collector, &parse_error)) { - std::cerr << "error parsing " << named_framework_to_proto_path_mappings_path_ - << " : " << parse_error << std::endl; - std::cerr.flush(); - } -} - -bool ImportWriter::ProtoFrameworkCollector::ConsumeLine( - const StringPiece& line, TProtoStringType* out_error) { - int offset = line.find(':'); - if (offset == StringPiece::npos) { - *out_error = - TProtoStringType("Framework/proto file mapping line without colon sign: '") + - TProtoStringType(line) + "'."; - return false; - } - StringPiece framework_name = line.substr(0, offset); - StringPiece proto_file_list = line.substr(offset + 1); - TrimWhitespace(&framework_name); - - int start = 0; - while (start < proto_file_list.length()) { - offset = proto_file_list.find(',', start); - if (offset == StringPiece::npos) { - offset = proto_file_list.length(); - } - - StringPiece proto_file = proto_file_list.substr(start, offset - start); - TrimWhitespace(&proto_file); - if (!proto_file.empty()) { - std::map<TProtoStringType, TProtoStringType>::iterator existing_entry = - map_->find(TProtoStringType(proto_file)); - if (existing_entry != map_->end()) { - std::cerr << "warning: duplicate proto file reference, replacing " - "framework entry for '" - << TProtoStringType(proto_file) << "' with '" << TProtoStringType(framework_name) - << "' (was '" << existing_entry->second << "')." << std::endl; - std::cerr.flush(); - } - - if (proto_file.find(' ') != StringPiece::npos) { - std::cerr << "note: framework mapping file had a proto file with a " - "space in, hopefully that isn't a missing comma: '" - << TProtoStringType(proto_file) << "'" << std::endl; - std::cerr.flush(); - } - - (*map_)[TProtoStringType(proto_file)] = TProtoStringType(framework_name); - } - - start = offset + 1; - } - - return true; -} - -} // namespace objectivec -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index afbf34b7ad..038fde5926 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -1,353 +1,2 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Helper functions for generating ObjectiveC code. - -#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ -#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ - -#include <string> -#include <vector> - -#include <google/protobuf/descriptor.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/io/zero_copy_stream.h> - -#include <google/protobuf/port_def.inc> - -namespace google { -namespace protobuf { -namespace compiler { -namespace objectivec { - -// Get/Set the path to a file to load for objc class prefix lookups. -TProtoStringType PROTOC_EXPORT GetPackageToPrefixMappingsPath(); -void PROTOC_EXPORT SetPackageToPrefixMappingsPath( - const TProtoStringType& file_path); -// Get/Set if the proto package should be used to make the default prefix for -// symbols. This will then impact most of the type naming apis below. It is done -// as a global to not break any other generator reusing the methods since they -// are exported. -bool PROTOC_EXPORT UseProtoPackageAsDefaultPrefix(); -void PROTOC_EXPORT SetUseProtoPackageAsDefaultPrefix(bool on_or_off); -// Get/Set the path to a file to load as exceptions when -// `UseProtoPackageAsDefaultPrefix()` is `true`. An empty string means there -// should be no exceptions. -TProtoStringType PROTOC_EXPORT GetProtoPackagePrefixExceptionList(); -void PROTOC_EXPORT SetProtoPackagePrefixExceptionList( - const TProtoStringType& file_path); - -// Generator Prefix Validation Options (see objectivec_generator.cc for a -// description of each): -struct Options { - Options(); - TProtoStringType expected_prefixes_path; - std::vector<TProtoStringType> expected_prefixes_suppressions; - bool prefixes_must_be_registered; - bool require_prefixes; -}; - -// Escape C++ trigraphs by escaping question marks to "\?". -TProtoStringType PROTOC_EXPORT EscapeTrigraphs(const TProtoStringType& to_escape); - -// Remove white space from either end of a StringPiece. -void PROTOC_EXPORT TrimWhitespace(StringPiece* input); - -// Returns true if the name requires a ns_returns_not_retained attribute applied -// to it. -bool PROTOC_EXPORT IsRetainedName(const TProtoStringType& name); - -// Returns true if the name starts with "init" and will need to have special -// handling under ARC. -bool PROTOC_EXPORT IsInitName(const TProtoStringType& name); - -// Gets the objc_class_prefix or the prefix made from the proto package. -TProtoStringType PROTOC_EXPORT FileClassPrefix(const FileDescriptor* file); - -// Gets the path of the file we're going to generate (sans the .pb.h -// extension). The path will be dependent on the objectivec package -// declared in the proto package. -TProtoStringType PROTOC_EXPORT FilePath(const FileDescriptor* file); - -// Just like FilePath(), but without the directory part. -TProtoStringType PROTOC_EXPORT FilePathBasename(const FileDescriptor* file); - -// Gets the name of the root class we'll generate in the file. This class -// is not meant for external consumption, but instead contains helpers that -// the rest of the classes need -TProtoStringType PROTOC_EXPORT FileClassName(const FileDescriptor* file); - -// These return the fully-qualified class name corresponding to the given -// descriptor. -TProtoStringType PROTOC_EXPORT ClassName(const Descriptor* descriptor); -TProtoStringType PROTOC_EXPORT ClassName(const Descriptor* descriptor, - TProtoStringType* out_suffix_added); -TProtoStringType PROTOC_EXPORT EnumName(const EnumDescriptor* descriptor); - -// Returns the fully-qualified name of the enum value corresponding to the -// the descriptor. -TProtoStringType PROTOC_EXPORT EnumValueName(const EnumValueDescriptor* descriptor); - -// Returns the name of the enum value corresponding to the descriptor. -TProtoStringType PROTOC_EXPORT EnumValueShortName(const EnumValueDescriptor* descriptor); - -// Reverse what an enum does. -TProtoStringType PROTOC_EXPORT UnCamelCaseEnumShortName(const TProtoStringType& name); - -// Returns the name to use for the extension (used as the method off the file's -// Root class). -TProtoStringType PROTOC_EXPORT ExtensionMethodName(const FieldDescriptor* descriptor); - -// Returns the transformed field name. -TProtoStringType PROTOC_EXPORT FieldName(const FieldDescriptor* field); -TProtoStringType PROTOC_EXPORT FieldNameCapitalized(const FieldDescriptor* field); - -// Returns the transformed oneof name. -TProtoStringType PROTOC_EXPORT OneofEnumName(const OneofDescriptor* descriptor); -TProtoStringType PROTOC_EXPORT OneofName(const OneofDescriptor* descriptor); -TProtoStringType PROTOC_EXPORT OneofNameCapitalized(const OneofDescriptor* descriptor); - -// Returns a symbol that can be used in C code to refer to an Objective C -// class without initializing the class. -TProtoStringType PROTOC_EXPORT ObjCClass(const TProtoStringType& class_name); - -// Declares an Objective C class without initializing the class so that it can -// be refrerred to by ObjCClass. -TProtoStringType PROTOC_EXPORT ObjCClassDeclaration(const TProtoStringType& class_name); - -inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) { - return file->syntax() == FileDescriptor::SYNTAX_PROTO3; -} - -inline bool IsMapEntryMessage(const Descriptor* descriptor) { - return descriptor->options().map_entry(); -} - -// Reverse of the above. -TProtoStringType PROTOC_EXPORT UnCamelCaseFieldName(const TProtoStringType& name, - const FieldDescriptor* field); - -enum ObjectiveCType { - OBJECTIVECTYPE_INT32, - OBJECTIVECTYPE_UINT32, - OBJECTIVECTYPE_INT64, - OBJECTIVECTYPE_UINT64, - OBJECTIVECTYPE_FLOAT, - OBJECTIVECTYPE_DOUBLE, - OBJECTIVECTYPE_BOOLEAN, - OBJECTIVECTYPE_STRING, - OBJECTIVECTYPE_DATA, - OBJECTIVECTYPE_ENUM, - OBJECTIVECTYPE_MESSAGE -}; - -enum FlagType { - FLAGTYPE_DESCRIPTOR_INITIALIZATION, - FLAGTYPE_EXTENSION, - FLAGTYPE_FIELD -}; - -template <class TDescriptor> -TProtoStringType GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, - const FileDescriptor* file = NULL, - bool preSpace = true, - bool postNewline = false) { - bool isDeprecated = descriptor->options().deprecated(); - // The file is only passed when checking Messages & Enums, so those types - // get tagged. At the moment, it doesn't seem to make sense to tag every - // field or enum value with when the file is deprecated. - bool isFileLevelDeprecation = false; - if (!isDeprecated && file) { - isFileLevelDeprecation = file->options().deprecated(); - isDeprecated = isFileLevelDeprecation; - } - if (isDeprecated) { - TProtoStringType message; - const FileDescriptor* sourceFile = descriptor->file(); - if (isFileLevelDeprecation) { - message = sourceFile->name() + " is deprecated."; - } else { - message = descriptor->full_name() + " is deprecated (see " + - sourceFile->name() + ")."; - } - - TProtoStringType result = TProtoStringType("GPB_DEPRECATED_MSG(\"") + message + "\")"; - if (preSpace) { - result.insert(0, " "); - } - if (postNewline) { - result.append("\n"); - } - return result; - } else { - return ""; - } -} - -TProtoStringType PROTOC_EXPORT GetCapitalizedType(const FieldDescriptor* field); - -ObjectiveCType PROTOC_EXPORT -GetObjectiveCType(FieldDescriptor::Type field_type); - -inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) { - return GetObjectiveCType(field->type()); -} - -bool PROTOC_EXPORT IsPrimitiveType(const FieldDescriptor* field); -bool PROTOC_EXPORT IsReferenceType(const FieldDescriptor* field); - -TProtoStringType PROTOC_EXPORT -GPBGenericValueFieldName(const FieldDescriptor* field); -TProtoStringType PROTOC_EXPORT DefaultValue(const FieldDescriptor* field); -bool PROTOC_EXPORT HasNonZeroDefaultValue(const FieldDescriptor* field); - -TProtoStringType PROTOC_EXPORT -BuildFlagsString(const FlagType type, const std::vector<TProtoStringType>& strings); - -// Builds HeaderDoc/appledoc style comments out of the comments in the .proto -// file. -TProtoStringType PROTOC_EXPORT BuildCommentsString(const SourceLocation& location, - bool prefer_single_line); - -// The name the commonly used by the library when built as a framework. -// This lines up to the name used in the CocoaPod. -extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName; -// Returns the CPP symbol name to use as the gate for framework style imports -// for the given framework name to use. -TProtoStringType PROTOC_EXPORT -ProtobufFrameworkImportSymbol(const TProtoStringType& framework_name); - -// Checks if the file is one of the proto's bundled with the library. -bool PROTOC_EXPORT -IsProtobufLibraryBundledProtoFile(const FileDescriptor* file); - -// Checks the prefix for the given files and outputs any warnings as needed. If -// there are flat out errors, then out_error is filled in with the first error -// and the result is false. -bool PROTOC_EXPORT ValidateObjCClassPrefixes( - const std::vector<const FileDescriptor*>& files, - const Options& validation_options, TProtoStringType* out_error); -// Same was the other ValidateObjCClassPrefixes() calls, but the options all -// come from the environment variables. -bool PROTOC_EXPORT ValidateObjCClassPrefixes( - const std::vector<const FileDescriptor*>& files, TProtoStringType* out_error); - -// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform -// the input into the expected output. -class PROTOC_EXPORT TextFormatDecodeData { - public: - TextFormatDecodeData(); - ~TextFormatDecodeData(); - - TextFormatDecodeData(const TextFormatDecodeData&) = delete; - TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete; - - void AddString(arc_i32 key, const TProtoStringType& input_for_decode, - const TProtoStringType& desired_output); - size_t num_entries() const { return entries_.size(); } - TProtoStringType Data() const; - - static TProtoStringType DecodeDataForString(const TProtoStringType& input_for_decode, - const TProtoStringType& desired_output); - - private: - typedef std::pair<arc_i32, TProtoStringType> DataEntry; - std::vector<DataEntry> entries_; -}; - -// Helper for parsing simple files. -class PROTOC_EXPORT LineConsumer { - public: - LineConsumer(); - virtual ~LineConsumer(); - virtual bool ConsumeLine(const StringPiece& line, TProtoStringType* out_error) = 0; -}; - -bool PROTOC_EXPORT ParseSimpleFile(const TProtoStringType& path, - LineConsumer* line_consumer, - TProtoStringType* out_error); - -bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream, - const TProtoStringType& stream_name, - LineConsumer* line_consumer, - TProtoStringType* out_error); - -// Helper class for parsing framework import mappings and generating -// import statements. -class PROTOC_EXPORT ImportWriter { - public: - ImportWriter(const TProtoStringType& generate_for_named_framework, - const TProtoStringType& named_framework_to_proto_path_mappings_path, - const TProtoStringType& runtime_import_prefix, - bool include_wkt_imports); - ~ImportWriter(); - - void AddFile(const FileDescriptor* file, const TProtoStringType& header_extension); - void Print(io::Printer* printer) const; - - static void PrintRuntimeImports(io::Printer* printer, - const std::vector<TProtoStringType>& header_to_import, - const TProtoStringType& runtime_import_prefix, - bool default_cpp_symbol = false); - - private: - class ProtoFrameworkCollector : public LineConsumer { - public: - ProtoFrameworkCollector(std::map<TProtoStringType, TProtoStringType>* inout_proto_file_to_framework_name) - : map_(inout_proto_file_to_framework_name) {} - - virtual bool ConsumeLine(const StringPiece& line, TProtoStringType* out_error) override; - - private: - std::map<TProtoStringType, TProtoStringType>* map_; - }; - - void ParseFrameworkMappings(); - - const TProtoStringType generate_for_named_framework_; - const TProtoStringType named_framework_to_proto_path_mappings_path_; - const TProtoStringType runtime_import_prefix_; - const bool include_wkt_imports_; - std::map<TProtoStringType, TProtoStringType> proto_file_to_framework_name_; - bool need_to_parse_mapping_file_; - - std::vector<TProtoStringType> protobuf_imports_; - std::vector<TProtoStringType> other_framework_imports_; - std::vector<TProtoStringType> other_imports_; -}; - -} // namespace objectivec -} // namespace compiler -} // namespace protobuf -} // namespace google - -#include <google/protobuf/port_undef.inc> - -#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ +#include "helpers.h" +#include "names.h"
\ No newline at end of file diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message.cc deleted file mode 100644 index bf73592e56..0000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ /dev/null @@ -1,633 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <algorithm> -#include <iostream> -#include <sstream> - -#include <google/protobuf/compiler/objectivec/objectivec_message.h> -#include <google/protobuf/compiler/objectivec/objectivec_enum.h> -#include <google/protobuf/compiler/objectivec/objectivec_extension.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/stubs/stl_util.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/descriptor.pb.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace objectivec { - -namespace { -struct FieldOrderingByNumber { - inline bool operator()(const FieldDescriptor* a, - const FieldDescriptor* b) const { - return a->number() < b->number(); - } -}; - -int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { - // The first item in the object structure is our uint32[] for has bits. - // We then want to order things to make the instances as small as - // possible. So we follow the has bits with: - // 1. Anything always 4 bytes - float, *32, enums - // 2. Anything that is always a pointer (they will be 8 bytes on 64 bit - // builds and 4 bytes on 32bit builds. - // 3. Anything always 8 bytes - double, *64 - // - // NOTE: Bools aren't listed, they were stored in the has bits. - // - // Why? Using 64bit builds as an example, this means worse case, we have - // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes - // are wasted before the 4 byte values. Then if we have an odd number of - // those 4 byte values, the 8 byte values will be pushed down by 32bits to - // keep them aligned. But the structure will end 8 byte aligned, so no - // waste on the end. If you did the reverse order, you could waste 4 bytes - // before the first 8 byte value (after the has array), then a single - // bool on the end would need 7 bytes of padding to make the overall - // structure 8 byte aligned; so 11 bytes, wasted total. - - // Anything repeated is a GPB*Array/NSArray, so pointer. - if (descriptor->is_repeated()) { - return 3; - } - - switch (descriptor->type()) { - // All always 8 bytes. - case FieldDescriptor::TYPE_DOUBLE: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_FIXED64: - return 4; - - // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes - // depending on the build architecture. - case FieldDescriptor::TYPE_GROUP: - case FieldDescriptor::TYPE_MESSAGE: - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - return 3; - - // All always 4 bytes (enums are int32s). - case FieldDescriptor::TYPE_FLOAT: - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_SFIXED32: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_ENUM: - return 2; - - // 0 bytes. Stored in the has bits. - case FieldDescriptor::TYPE_BOOL: - return 99; // End of the list (doesn't really matter). - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return 0; -} - -struct FieldOrderingByStorageSize { - inline bool operator()(const FieldDescriptor* a, - const FieldDescriptor* b) const { - // Order by grouping. - const int order_group_a = OrderGroupForFieldDescriptor(a); - const int order_group_b = OrderGroupForFieldDescriptor(b); - if (order_group_a != order_group_b) { - return order_group_a < order_group_b; - } - // Within the group, order by field number (provides stable ordering). - return a->number() < b->number(); - } -}; - -struct ExtensionRangeOrdering { - bool operator()(const Descriptor::ExtensionRange* a, - const Descriptor::ExtensionRange* b) const { - return a->start < b->start; - } -}; - -// Sort the fields of the given Descriptor by number into a new[]'d array -// and return it. -const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { - const FieldDescriptor** fields = - new const FieldDescriptor* [descriptor->field_count()]; - for (int i = 0; i < descriptor->field_count(); i++) { - fields[i] = descriptor->field(i); - } - std::sort(fields, fields + descriptor->field_count(), FieldOrderingByNumber()); - return fields; -} - -// Sort the fields of the given Descriptor by storage size into a new[]'d -// array and return it. -const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) { - const FieldDescriptor** fields = - new const FieldDescriptor* [descriptor->field_count()]; - for (int i = 0; i < descriptor->field_count(); i++) { - fields[i] = descriptor->field(i); - } - std::sort(fields, fields + descriptor->field_count(), - FieldOrderingByStorageSize()); - return fields; -} -} // namespace - -MessageGenerator::MessageGenerator(const TProtoStringType& root_classname, - const Descriptor* descriptor) - : root_classname_(root_classname), - descriptor_(descriptor), - field_generators_(descriptor), - class_name_(ClassName(descriptor_)), - deprecated_attribute_(GetOptionalDeprecatedAttribute( - descriptor, descriptor->file(), false, true)) { - for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators_.emplace_back( - new ExtensionGenerator(class_name_, descriptor_->extension(i))); - } - - for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { - OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i)); - oneof_generators_.emplace_back(generator); - } - - for (int i = 0; i < descriptor_->enum_type_count(); i++) { - EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i)); - enum_generators_.emplace_back(generator); - } - - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - MessageGenerator* generator = - new MessageGenerator(root_classname_, - descriptor_->nested_type(i)); - nested_message_generators_.emplace_back(generator); - } -} - -MessageGenerator::~MessageGenerator() {} - -void MessageGenerator::GenerateStaticVariablesInitialization( - io::Printer* printer) { - for (const auto& generator : extension_generators_) { - generator->GenerateStaticVariablesInitialization(printer); - } - - for (const auto& generator : nested_message_generators_) { - generator->GenerateStaticVariablesInitialization(printer); - } -} - -void MessageGenerator::DetermineForwardDeclarations( - std::set<TProtoStringType>* fwd_decls, - bool include_external_types) { - if (!IsMapEntryMessage(descriptor_)) { - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* fieldDescriptor = descriptor_->field(i); - field_generators_.get(fieldDescriptor) - .DetermineForwardDeclarations(fwd_decls, include_external_types); - } - } - - for (const auto& generator : nested_message_generators_) { - generator->DetermineForwardDeclarations(fwd_decls, include_external_types); - } -} - -void MessageGenerator::DetermineObjectiveCClassDefinitions( - std::set<TProtoStringType>* fwd_decls) { - if (!IsMapEntryMessage(descriptor_)) { - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* fieldDescriptor = descriptor_->field(i); - field_generators_.get(fieldDescriptor) - .DetermineObjectiveCClassDefinitions(fwd_decls); - } - } - - for (const auto& generator : extension_generators_) { - generator->DetermineObjectiveCClassDefinitions(fwd_decls); - } - - for (const auto& generator : nested_message_generators_) { - generator->DetermineObjectiveCClassDefinitions(fwd_decls); - } - - const Descriptor* containing_descriptor = descriptor_->containing_type(); - if (containing_descriptor != NULL) { - TProtoStringType containing_class = ClassName(containing_descriptor); - fwd_decls->insert(ObjCClassDeclaration(containing_class)); - } -} - -bool MessageGenerator::IncludesOneOfDefinition() const { - if (!oneof_generators_.empty()) { - return true; - } - - for (const auto& generator : nested_message_generators_) { - if (generator->IncludesOneOfDefinition()) { - return true; - } - } - - return false; -} - -void MessageGenerator::GenerateEnumHeader(io::Printer* printer) { - for (const auto& generator : enum_generators_) { - generator->GenerateHeader(printer); - } - - for (const auto& generator : nested_message_generators_) { - generator->GenerateEnumHeader(printer); - } -} - -void MessageGenerator::GenerateExtensionRegistrationSource( - io::Printer* printer) { - for (const auto& generator : extension_generators_) { - generator->GenerateRegistrationSource(printer); - } - - for (const auto& generator : nested_message_generators_) { - generator->GenerateExtensionRegistrationSource(printer); - } -} - -void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { - // This a a map entry message, just recurse and do nothing directly. - if (IsMapEntryMessage(descriptor_)) { - for (const auto& generator : nested_message_generators_) { - generator->GenerateMessageHeader(printer); - } - return; - } - - printer->Print( - "#pragma mark - $classname$\n" - "\n", - "classname", class_name_); - - if (descriptor_->field_count()) { - std::unique_ptr<const FieldDescriptor*[]> sorted_fields( - SortFieldsByNumber(descriptor_)); - - printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n", - "classname", class_name_); - printer->Indent(); - - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(sorted_fields[i]) - .GenerateFieldNumberConstant(printer); - } - - printer->Outdent(); - printer->Print("};\n\n"); - } - - for (const auto& generator : oneof_generators_) { - generator->GenerateCaseEnum(printer); - } - - TProtoStringType message_comments; - SourceLocation location; - if (descriptor_->GetSourceLocation(&location)) { - message_comments = BuildCommentsString(location, false); - } else { - message_comments = ""; - } - - printer->Print( - "$comments$$deprecated_attribute$GPB_FINAL @interface $classname$ : GPBMessage\n\n", - "classname", class_name_, - "deprecated_attribute", deprecated_attribute_, - "comments", message_comments); - - std::vector<char> seen_oneofs(oneof_generators_.size(), 0); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - const OneofDescriptor* oneof = field->real_containing_oneof(); - if (oneof) { - const int oneof_index = oneof->index(); - if (!seen_oneofs[oneof_index]) { - seen_oneofs[oneof_index] = 1; - oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration( - printer); - } - } - field_generators_.get(field).GeneratePropertyDeclaration(printer); - } - - printer->Print("@end\n\n"); - - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateCFunctionDeclarations(printer); - } - - if (!oneof_generators_.empty()) { - for (const auto& generator : oneof_generators_) { - generator->GenerateClearFunctionDeclaration(printer); - } - printer->Print("\n"); - } - - if (descriptor_->extension_count() > 0) { - printer->Print("@interface $classname$ (DynamicMethods)\n\n", - "classname", class_name_); - for (const auto& generator : extension_generators_) { - generator->GenerateMembersHeader(printer); - } - printer->Print("@end\n\n"); - } - - for (const auto& generator : nested_message_generators_) { - generator->GenerateMessageHeader(printer); - } -} - -void MessageGenerator::GenerateSource(io::Printer* printer) { - if (!IsMapEntryMessage(descriptor_)) { - printer->Print( - "#pragma mark - $classname$\n" - "\n", - "classname", class_name_); - - if (!deprecated_attribute_.empty()) { - // No warnings when compiling the impl of this deprecated class. - printer->Print( - "#pragma clang diagnostic push\n" - "#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n" - "\n"); - } - - printer->Print("@implementation $classname$\n\n", - "classname", class_name_); - - for (const auto& generator : oneof_generators_) { - generator->GeneratePropertyImplementation(printer); - } - - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GeneratePropertyImplementation(printer); - } - - std::unique_ptr<const FieldDescriptor*[]> sorted_fields( - SortFieldsByNumber(descriptor_)); - std::unique_ptr<const FieldDescriptor*[]> size_order_fields( - SortFieldsByStorageSize(descriptor_)); - - std::vector<const Descriptor::ExtensionRange*> sorted_extensions; - sorted_extensions.reserve(descriptor_->extension_range_count()); - for (int i = 0; i < descriptor_->extension_range_count(); ++i) { - sorted_extensions.push_back(descriptor_->extension_range(i)); - } - - std::sort(sorted_extensions.begin(), sorted_extensions.end(), - ExtensionRangeOrdering()); - - // Assign has bits: - // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing - // who needs has bits and assigning them. - // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative - // index that groups all the elements in the oneof. - size_t num_has_bits = field_generators_.CalculateHasBits(); - size_t sizeof_has_storage = (num_has_bits + 31) / 32; - if (sizeof_has_storage == 0) { - // In the case where no field needs has bits, don't let the _has_storage_ - // end up as zero length (zero length arrays are sort of a grey area - // since it has to be at the start of the struct). This also ensures a - // field with only oneofs keeps the required negative indices they need. - sizeof_has_storage = 1; - } - // Tell all the fields the oneof base. - for (const auto& generator : oneof_generators_) { - generator->SetOneofIndexBase(sizeof_has_storage); - } - field_generators_.SetOneofIndexBase(sizeof_has_storage); - // sizeof_has_storage needs enough bits for the single fields that aren't in - // any oneof, and then one int32 for each oneof (to store the field number). - sizeof_has_storage += oneof_generators_.size(); - - printer->Print( - "\n" - "typedef struct $classname$__storage_ {\n" - " arc_ui32 _has_storage_[$sizeof_has_storage$];\n", - "classname", class_name_, - "sizeof_has_storage", StrCat(sizeof_has_storage)); - printer->Indent(); - - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(size_order_fields[i]) - .GenerateFieldStorageDeclaration(printer); - } - printer->Outdent(); - - printer->Print("} $classname$__storage_;\n\n", "classname", class_name_); - - - printer->Print( - "// This method is threadsafe because it is initially called\n" - "// in +initialize for each subclass.\n" - "+ (GPBDescriptor *)descriptor {\n" - " static GPBDescriptor *descriptor = nil;\n" - " if (!descriptor) {\n"); - - TextFormatDecodeData text_format_decode_data; - bool has_fields = descriptor_->field_count() > 0; - bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault(); - TProtoStringType field_description_type; - if (need_defaults) { - field_description_type = "GPBMessageFieldDescriptionWithDefault"; - } else { - field_description_type = "GPBMessageFieldDescription"; - } - if (has_fields) { - printer->Indent(); - printer->Indent(); - printer->Print( - "static $field_description_type$ fields[] = {\n", - "field_description_type", field_description_type); - printer->Indent(); - for (int i = 0; i < descriptor_->field_count(); ++i) { - const FieldGenerator& field_generator = - field_generators_.get(sorted_fields[i]); - field_generator.GenerateFieldDescription(printer, need_defaults); - if (field_generator.needs_textformat_name_support()) { - text_format_decode_data.AddString(sorted_fields[i]->number(), - field_generator.generated_objc_name(), - field_generator.raw_field_name()); - } - } - printer->Outdent(); - printer->Print( - "};\n"); - printer->Outdent(); - printer->Outdent(); - } - - std::map<TProtoStringType, TProtoStringType> vars; - vars["classname"] = class_name_; - vars["rootclassname"] = root_classname_; - vars["fields"] = has_fields ? "fields" : "NULL"; - if (has_fields) { - vars["fields_count"] = - "(arc_ui32)(sizeof(fields) / sizeof(" + field_description_type + "))"; - } else { - vars["fields_count"] = "0"; - } - - std::vector<TProtoStringType> init_flags; - init_flags.push_back("GPBDescriptorInitializationFlag_UsesClassRefs"); - init_flags.push_back("GPBDescriptorInitializationFlag_Proto3OptionalKnown"); - if (need_defaults) { - init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault"); - } - if (descriptor_->options().message_set_wire_format()) { - init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat"); - } - vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION, - init_flags); - - printer->Print( - vars, - " GPBDescriptor *localDescriptor =\n" - " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" - " rootClass:[$rootclassname$ class]\n" - " file:$rootclassname$_FileDescriptor()\n" - " fields:$fields$\n" - " fieldCount:$fields_count$\n" - " storageSize:sizeof($classname$__storage_)\n" - " flags:$init_flags$];\n"); - if (!oneof_generators_.empty()) { - printer->Print( - " static const char *oneofs[] = {\n"); - for (const auto& generator : oneof_generators_) { - printer->Print(" \"$name$\",\n", "name", - generator->DescriptorName()); - } - printer->Print( - " };\n" - " [localDescriptor setupOneofs:oneofs\n" - " count:(arc_ui32)(sizeof(oneofs) / sizeof(char*))\n" - " firstHasIndex:$first_has_index$];\n", - "first_has_index", oneof_generators_[0]->HasIndexAsString()); - } - if (text_format_decode_data.num_entries() != 0) { - const TProtoStringType text_format_data_str(text_format_decode_data.Data()); - printer->Print( - "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" - " static const char *extraTextFormatInfo ="); - static const int kBytesPerLine = 40; // allow for escaping - for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) { - printer->Print( - "\n \"$data$\"", - "data", EscapeTrigraphs( - CEscape(text_format_data_str.substr(i, kBytesPerLine)))); - } - printer->Print( - ";\n" - " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n" - "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"); - } - if (!sorted_extensions.empty()) { - printer->Print( - " static const GPBExtensionRange ranges[] = {\n"); - for (int i = 0; i < sorted_extensions.size(); i++) { - printer->Print(" { .start = $start$, .end = $end$ },\n", - "start", StrCat(sorted_extensions[i]->start), - "end", StrCat(sorted_extensions[i]->end)); - } - printer->Print( - " };\n" - " [localDescriptor setupExtensionRanges:ranges\n" - " count:(arc_ui32)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); - } - if (descriptor_->containing_type() != NULL) { - TProtoStringType containing_class = ClassName(descriptor_->containing_type()); - TProtoStringType parent_class_ref = ObjCClass(containing_class); - printer->Print( - " [localDescriptor setupContainingMessageClass:$parent_class_ref$];\n", - "parent_class_ref", parent_class_ref); - } - TProtoStringType suffix_added; - ClassName(descriptor_, &suffix_added); - if (!suffix_added.empty()) { - printer->Print( - " [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n", - "suffix", suffix_added); - } - printer->Print( - " #if defined(DEBUG) && DEBUG\n" - " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" - " #endif // DEBUG\n" - " descriptor = localDescriptor;\n" - " }\n" - " return descriptor;\n" - "}\n\n" - "@end\n\n"); - - if (!deprecated_attribute_.empty()) { - printer->Print( - "#pragma clang diagnostic pop\n" - "\n"); - } - - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateCFunctionImplementations(printer); - } - - for (const auto& generator : oneof_generators_) { - generator->GenerateClearFunctionImplementation(printer); - } - } - - for (const auto& generator : enum_generators_) { - generator->GenerateSource(printer); - } - - for (const auto& generator : nested_message_generators_) { - generator->GenerateSource(printer); - } -} - -} // namespace objectivec -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h deleted file mode 100644 index 163304665c..0000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h +++ /dev/null @@ -1,197 +0,0 @@ -// NSObject methods -// Autogenerated by method_dump.sh. Do not edit by hand. -// Date: Thu Nov 1 14:12:16 PDT 2018 -// macOS: MacOSX10.14.sdk -// iOS: iPhoneSimulator12.1.sdk - -const char* const kNSObjectMethodsList[] = { - "CAMLType", - "CA_copyRenderValue", - "CA_prepareRenderValue", - "NS_copyCGImage", - "NS_tiledLayerVisibleRect", - "___tryRetain_OA", - "__autorelease_OA", - "__dealloc_zombie", - "__release_OA", - "__retain_OA", - "_accessibilityFinalize", - "_accessibilityIsTableViewDescendant", - "_accessibilityUIElementSpecifier", - "_accessibilityUseConvenienceAPI", - "_allowsDirectEncoding", - "_asScriptTerminologyNameArray", - "_asScriptTerminologyNameString", - "_bindingAdaptor", - "_cfTypeID", - "_copyDescription", - "_destroyObserverList", - "_didEndKeyValueObserving", - "_implicitObservationInfo", - "_internalAccessibilityAttributedHint", - "_internalAccessibilityAttributedLabel", - "_internalAccessibilityAttributedValue", - "_isAXConnector", - "_isAccessibilityContainerSectionCandidate", - "_isAccessibilityContentNavigatorSectionCandidate", - "_isAccessibilityContentSectionCandidate", - "_isAccessibilityTopLevelNavigatorSectionCandidate", - "_isDeallocating", - "_isKVOA", - "_isToManyChangeInformation", - "_ivarDescription", - "_localClassNameForClass", - "_methodDescription", - "_observerStorage", - "_overrideUseFastBlockObservers", - "_propertyDescription", - "_releaseBindingAdaptor", - "_scriptingCount", - "_scriptingCountNonrecursively", - "_scriptingDebugDescription", - "_scriptingExists", - "_scriptingShouldCheckObjectIndexes", - "_shortMethodDescription", - "_shouldSearchChildrenForSection", - "_traitStorageList", - "_tryRetain", - "_ui_descriptionBuilder", - "_uikit_variesByTraitCollections", - "_web_description", - "_webkit_invokeOnMainThread", - "_willBeginKeyValueObserving", - "accessibilityActivate", - "accessibilityActivationPoint", - "accessibilityAllowsOverriddenAttributesWhenIgnored", - "accessibilityAssistiveTechnologyFocusedIdentifiers", - "accessibilityAttributedHint", - "accessibilityAttributedLabel", - "accessibilityAttributedValue", - "accessibilityContainer", - "accessibilityContainerType", - "accessibilityCustomActions", - "accessibilityCustomRotors", - "accessibilityDecrement", - "accessibilityDragSourceDescriptors", - "accessibilityDropPointDescriptors", - "accessibilityElementCount", - "accessibilityElementDidBecomeFocused", - "accessibilityElementDidLoseFocus", - "accessibilityElementIsFocused", - "accessibilityElements", - "accessibilityElementsHidden", - "accessibilityFrame", - "accessibilityHeaderElements", - "accessibilityHint", - "accessibilityIdentification", - "accessibilityIdentifier", - "accessibilityIncrement", - "accessibilityLabel", - "accessibilityLanguage", - "accessibilityLocalizedStringKey", - "accessibilityNavigationStyle", - "accessibilityOverriddenAttributes", - "accessibilityParameterizedAttributeNames", - "accessibilityPath", - "accessibilityPerformEscape", - "accessibilityPerformMagicTap", - "accessibilityPresenterProcessIdentifier", - "accessibilityShouldUseUniqueId", - "accessibilitySupportsNotifications", - "accessibilitySupportsOverriddenAttributes", - "accessibilityTemporaryChildren", - "accessibilityTraits", - "accessibilityValue", - "accessibilityViewIsModal", - "accessibilityVisibleArea", - "allPropertyKeys", - "allowsWeakReference", - "attributeKeys", - "autoContentAccessingProxy", - "autorelease", - "awakeFromNib", - "boolValueSafe", - "bs_encoded", - "bs_isPlistableType", - "bs_secureEncoded", - "cl_json_serializeKey", - "class", - "classCode", - "classDescription", - "classForArchiver", - "classForCoder", - "classForKeyedArchiver", - "classForPortCoder", - "className", - "clearProperties", - "copy", - "dealloc", - "debugDescription", - "defaultAccessibilityTraits", - "description", - "doubleValueSafe", - "entityName", - "exposedBindings", - "finalize", - "finishObserving", - "flushKeyBindings", - "hash", - "init", - "int64ValueSafe", - "isAccessibilityElement", - "isAccessibilityElementByDefault", - "isElementAccessibilityExposedToInterfaceBuilder", - "isFault", - "isNSArray__", - "isNSCFConstantString__", - "isNSData__", - "isNSDate__", - "isNSDictionary__", - "isNSNumber__", - "isNSObject__", - "isNSOrderedSet__", - "isNSSet__", - "isNSString__", - "isNSTimeZone__", - "isNSValue__", - "isProxy", - "mutableCopy", - "nilValueForKey", - "objectSpecifier", - "observationInfo", - "pep_onDetachedThread", - "pep_onMainThread", - "pep_onMainThreadIfNecessary", - "prepareForInterfaceBuilder", - "release", - "releaseOnMainThread", - "retain", - "retainCount", - "retainWeakReference", - "scriptingProperties", - "self", - "shouldGroupAccessibilityChildren", - "storedAccessibilityActivationPoint", - "storedAccessibilityContainerType", - "storedAccessibilityElementsHidden", - "storedAccessibilityFrame", - "storedAccessibilityNavigationStyle", - "storedAccessibilityTraits", - "storedAccessibilityViewIsModal", - "storedIsAccessibilityElement", - "storedShouldGroupAccessibilityChildren", - "stringValueSafe", - "superclass", - "toManyRelationshipKeys", - "toOneRelationshipKeys", - "traitStorageList", - "un_safeBoolValue", - "userInterfaceItemIdentifier", - "utf8ValueSafe", - "valuesForKeysWithDictionary", - "zone", -// Protocol: CAAnimatableValue -// Protocol: CARenderValue -// Protocol: NSObject -// Protocol: ROCKRemoteInvocationInterface -}; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/oneof.cc index 5197ff63a3..aa534d32f7 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/oneof.cc @@ -28,13 +28,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <map> +#include "google/protobuf/compiler/objectivec/oneof.h" + #include <string> -#include <google/protobuf/compiler/objectivec/objectivec_oneof.h> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -46,7 +47,7 @@ OneofGenerator::OneofGenerator(const OneofDescriptor* descriptor) variables_["enum_name"] = OneofEnumName(descriptor_); variables_["name"] = OneofName(descriptor_); variables_["capitalized_name"] = OneofNameCapitalized(descriptor_); - variables_["raw_index"] = StrCat(descriptor_->index()); + variables_["raw_index"] = y_absl::StrCat(descriptor_->index()); const Descriptor* msg_descriptor = descriptor_->containing_type(); variables_["owning_message_class"] = ClassName(msg_descriptor); @@ -60,63 +61,63 @@ OneofGenerator::OneofGenerator(const OneofDescriptor* descriptor) variables_["comments"] = comments; } -OneofGenerator::~OneofGenerator() {} - void OneofGenerator::SetOneofIndexBase(int index_base) { int index = descriptor_->index() + index_base; // Flip the sign to mark it as a oneof. - variables_["index"] = StrCat(-index); + variables_["index"] = y_absl::StrCat(-index); } -void OneofGenerator::GenerateCaseEnum(io::Printer* printer) { - printer->Print( - variables_, - "typedef GPB_ENUM($enum_name$) {\n"); +void OneofGenerator::GenerateCaseEnum(io::Printer* printer) const { + printer->Print(variables_, "typedef GPB_ENUM($enum_name$) {\n"); printer->Indent(); - printer->Print( - variables_, - "$enum_name$_GPBUnsetOneOfCase = 0,\n"); - TProtoStringType enum_name = variables_["enum_name"]; + printer->Print(variables_, "$enum_name$_GPBUnsetOneOfCase = 0,\n"); + TProtoStringType enum_name = variables_.find("enum_name")->second; for (int j = 0; j < descriptor_->field_count(); j++) { const FieldDescriptor* field = descriptor_->field(j); TProtoStringType field_name = FieldNameCapitalized(field); - printer->Print( - "$enum_name$_$field_name$ = $field_number$,\n", - "enum_name", enum_name, - "field_name", field_name, - "field_number", StrCat(field->number())); + printer->Print("$enum_name$_$field_name$ = $field_number$,\n", "enum_name", + enum_name, "field_name", field_name, "field_number", + y_absl::StrCat(field->number())); } printer->Outdent(); + // clang-format off printer->Print( "};\n" "\n"); + // clang-format on } void OneofGenerator::GeneratePublicCasePropertyDeclaration( - io::Printer* printer) { + io::Printer* printer) const { + // clang-format off printer->Print( variables_, "$comments$" "@property(nonatomic, readonly) $enum_name$ $name$OneOfCase;\n" "\n"); + // clang-format on } -void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) { +void OneofGenerator::GenerateClearFunctionDeclaration( + io::Printer* printer) const { + // clang-format off printer->Print( variables_, "/**\n" " * Clears whatever value was set for the oneof '$name$'.\n" " **/\n" "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n"); + // clang-format on } -void OneofGenerator::GeneratePropertyImplementation(io::Printer* printer) { - printer->Print( - variables_, - "@dynamic $name$OneOfCase;\n"); +void OneofGenerator::GeneratePropertyImplementation( + io::Printer* printer) const { + printer->Print(variables_, "@dynamic $name$OneOfCase;\n"); } -void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) { +void OneofGenerator::GenerateClearFunctionImplementation( + io::Printer* printer) const { + // clang-format off printer->Print( variables_, "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n" @@ -124,13 +125,14 @@ void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) { " GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:$raw_index$];\n" " GPBClearOneof(message, oneof);\n" "}\n"); + // clang-format on } -TProtoStringType OneofGenerator::DescriptorName(void) const { +TProtoStringType OneofGenerator::DescriptorName() const { return variables_.find("name")->second; } -TProtoStringType OneofGenerator::HasIndexAsString(void) const { +TProtoStringType OneofGenerator::HasIndexAsString() const { return variables_.find("index")->second; } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/oneof.h index 4173a0325c..411f832f21 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_oneof.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/oneof.h @@ -32,10 +32,11 @@ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__ #include <string> -#include <set> #include <vector> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/io/printer.h> + +#include "y_absl/container/flat_hash_map.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -45,27 +46,27 @@ namespace objectivec { class OneofGenerator { public: explicit OneofGenerator(const OneofDescriptor* descriptor); - ~OneofGenerator(); + ~OneofGenerator() = default; OneofGenerator(const OneofGenerator&) = delete; OneofGenerator& operator=(const OneofGenerator&) = delete; void SetOneofIndexBase(int index_base); - void GenerateCaseEnum(io::Printer* printer); + void GenerateCaseEnum(io::Printer* printer) const; - void GeneratePublicCasePropertyDeclaration(io::Printer* printer); - void GenerateClearFunctionDeclaration(io::Printer* printer); + void GeneratePublicCasePropertyDeclaration(io::Printer* printer) const; + void GenerateClearFunctionDeclaration(io::Printer* printer) const; - void GeneratePropertyImplementation(io::Printer* printer); - void GenerateClearFunctionImplementation(io::Printer* printer); + void GeneratePropertyImplementation(io::Printer* printer) const; + void GenerateClearFunctionImplementation(io::Printer* printer) const; - TProtoStringType DescriptorName(void) const; - TProtoStringType HasIndexAsString(void) const; + TProtoStringType DescriptorName() const; + TProtoStringType HasIndexAsString() const; private: const OneofDescriptor* descriptor_; - std::map<TProtoStringType, TProtoStringType> variables_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> variables_; }; } // namespace objectivec diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/options.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/options.h new file mode 100644 index 0000000000..d0f7ee0c76 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/options.h @@ -0,0 +1,57 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_OPTIONS_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_OPTIONS_H__ + +#include <string> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// Generation options, documented within generator.cc. +struct GenerationOptions { + TProtoStringType generate_for_named_framework; + TProtoStringType named_framework_to_proto_path_mappings_path; + TProtoStringType runtime_import_prefix; + // TODO(thomasvl): Eventually flip this default to false for better interop + // with Swift if proto usages span modules made from ObjC sources. + bool headers_use_forward_declarations = true; + bool experimental_multi_source_generation = false; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_OPTIONS_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/primitive_field.cc index f83e2691ae..aa839ecf2b 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/primitive_field.cc @@ -28,22 +28,21 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <map> +#include "google/protobuf/compiler/objectivec/primitive_field.h" + #include <string> -#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> -#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_log.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace objectivec { -using internal::WireFormat; -using internal::WireFormatLite; - namespace { const char* PrimitiveTypeName(const FieldDescriptor* descriptor) { @@ -70,13 +69,13 @@ const char* PrimitiveTypeName(const FieldDescriptor* descriptor) { case OBJECTIVECTYPE_ENUM: return "arc_i32"; case OBJECTIVECTYPE_MESSAGE: - return NULL; // Messages go through objectivec_message_field.cc|h. + return nullptr; // Messages go through message_field.cc|h. } // Some compilers report reaching end of function even though all cases of // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; + Y_ABSL_LOG(FATAL) << "Can't get here."; + return nullptr; } const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) { @@ -103,18 +102,19 @@ const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) { case OBJECTIVECTYPE_ENUM: return "Enum"; case OBJECTIVECTYPE_MESSAGE: - // Want NSArray (but goes through objectivec_message_field.cc|h). + // Want NSArray (but goes through message_field.cc|h). return ""; } // Some compilers report reaching end of function even though all cases of // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; + Y_ABSL_LOG(FATAL) << "Can't get here."; + return nullptr; } -void SetPrimitiveVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables) { +void SetPrimitiveVariables( + const FieldDescriptor* descriptor, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables) { TProtoStringType primitive_name = PrimitiveTypeName(descriptor); (*variables)["type"] = primitive_name; (*variables)["storage_type"] = primitive_name; @@ -128,8 +128,6 @@ PrimitiveFieldGenerator::PrimitiveFieldGenerator( SetPrimitiveVariables(descriptor, &variables_); } -PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} - void PrimitiveFieldGenerator::GenerateFieldStorageDeclaration( io::Printer* printer) const { if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { @@ -139,7 +137,7 @@ void PrimitiveFieldGenerator::GenerateFieldStorageDeclaration( } } -int PrimitiveFieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { +int PrimitiveFieldGenerator::ExtraRuntimeHasBitsNeeded() const { if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { // Reserve a bit for the storage of the boolean. return 1; @@ -147,10 +145,10 @@ int PrimitiveFieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { return 0; } -void PrimitiveFieldGenerator::SetExtraRuntimeHasBitsBase(int has_base) { +void PrimitiveFieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) { if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { // Set into the offset the has bit to use for the actual value. - variables_["storage_offset_value"] = StrCat(has_base); + variables_["storage_offset_value"] = y_absl::StrCat(index_base); variables_["storage_offset_comment"] = " // Stored in _has_storage_ to save space."; } @@ -163,8 +161,6 @@ PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator( variables_["property_storage_attribute"] = "copy"; } -PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {} - RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( const FieldDescriptor* descriptor) : RepeatedFieldGenerator(descriptor) { @@ -172,16 +168,15 @@ RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( TProtoStringType base_name = PrimitiveArrayTypeName(descriptor); if (base_name.length()) { - variables_["array_storage_type"] = "GPB" + base_name + "Array"; + variables_["array_storage_type"] = y_absl::StrCat("GPB", base_name, "Array"); } else { + TProtoStringType storage_type = variables_["storage_type"]; variables_["array_storage_type"] = "NSMutableArray"; variables_["array_property_type"] = - "NSMutableArray<" + variables_["storage_type"] + "*>"; + y_absl::StrCat("NSMutableArray<", storage_type, "*>"); } } -RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/primitive_field.h index 06a1528a82..e6916055cd 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/primitive_field.h @@ -31,7 +31,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ -#include <google/protobuf/compiler/objectivec/objectivec_field.h> +#include "google/protobuf/compiler/objectivec/field.h" namespace google { namespace protobuf { @@ -43,15 +43,15 @@ class PrimitiveFieldGenerator : public SingleFieldGenerator { protected: explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor); - virtual ~PrimitiveFieldGenerator(); + ~PrimitiveFieldGenerator() override = default; PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete; PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete; - virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + void GenerateFieldStorageDeclaration(io::Printer* printer) const override; - virtual int ExtraRuntimeHasBitsNeeded(void) const override; - virtual void SetExtraRuntimeHasBitsBase(int index_base) override; + int ExtraRuntimeHasBitsNeeded() const override; + void SetExtraRuntimeHasBitsBase(int index_base) override; }; class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator { @@ -59,7 +59,7 @@ class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator { protected: explicit PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor); - virtual ~PrimitiveObjFieldGenerator(); + ~PrimitiveObjFieldGenerator() override = default; PrimitiveObjFieldGenerator(const PrimitiveObjFieldGenerator&) = delete; PrimitiveObjFieldGenerator& operator=(const PrimitiveObjFieldGenerator&) = @@ -71,7 +71,7 @@ class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator { protected: explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor); - virtual ~RepeatedPrimitiveFieldGenerator(); + ~RepeatedPrimitiveFieldGenerator() override = default; RepeatedPrimitiveFieldGenerator(const RepeatedPrimitiveFieldGenerator&) = delete; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc new file mode 100644 index 0000000000..f254c6093f --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc @@ -0,0 +1,254 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" + +#include <iostream> +#include <ostream> +#include <sstream> +#include <string> +#include <vector> + +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/escaping.h" +#include "y_absl/strings/match.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +// Helper to build up the decode data for a string. +class DecodeDataBuilder { + public: + DecodeDataBuilder() { Reset(); } + + bool AddCharacter(char desired, char input); + void AddUnderscore() { + Push(); + need_underscore_ = true; + } + TProtoStringType Finish() { + Push(); + return decode_data_; + } + + private: + static constexpr uint8_t kAddUnderscore = 0x80; + + static constexpr uint8_t kOpAsIs = 0x00; + static constexpr uint8_t kOpFirstUpper = 0x40; + static constexpr uint8_t kOpFirstLower = 0x20; + static constexpr uint8_t kOpAllUpper = 0x60; + + static constexpr int kMaxSegmentLen = 0x1f; + + void AddChar(const char desired) { + ++segment_len_; + is_all_upper_ &= y_absl::ascii_isupper(desired); + } + + void Push() { + uint8_t op = (op_ | segment_len_); + if (need_underscore_) op |= kAddUnderscore; + if (op != 0) { + decode_data_ += (char)op; + } + Reset(); + } + + bool AddFirst(const char desired, const char input) { + if (desired == input) { + op_ = kOpAsIs; + } else if (desired == y_absl::ascii_toupper(input)) { + op_ = kOpFirstUpper; + } else if (desired == y_absl::ascii_tolower(input)) { + op_ = kOpFirstLower; + } else { + // Can't be transformed to match. + return false; + } + AddChar(desired); + return true; + } + + void Reset() { + need_underscore_ = false; + op_ = 0; + segment_len_ = 0; + is_all_upper_ = true; + } + + bool need_underscore_; + bool is_all_upper_; + uint8_t op_; + int segment_len_; + + TProtoStringType decode_data_; +}; + +bool DecodeDataBuilder::AddCharacter(char desired, char input) { + // If we've hit the max size, push to start a new segment. + if (segment_len_ == kMaxSegmentLen) { + Push(); + } + if (segment_len_ == 0) { + return AddFirst(desired, input); + } + + // Desired and input match... + if (desired == input) { + // If we aren't transforming it, or we're upper casing it and it is + // supposed to be uppercase; just add it to the segment. + if ((op_ != kOpAllUpper) || y_absl::ascii_isupper(desired)) { + AddChar(desired); + return true; + } + + // Add the current segment, and start the next one. + Push(); + return AddFirst(desired, input); + } + + // If we need to uppercase, and everything so far has been uppercase, + // promote op to AllUpper. + if ((desired == y_absl::ascii_toupper(input)) && is_all_upper_) { + op_ = kOpAllUpper; + AddChar(desired); + return true; + } + + // Give up, push and start a new segment. + Push(); + return AddFirst(desired, input); +} + +// If decode data can't be generated, a directive for the raw string +// is used instead. +TProtoStringType DirectDecodeString(const TProtoStringType& str) { + TProtoStringType result; + result += (char)'\0'; // Marker for full string. + result += str; + result += (char)'\0'; // End of string. + return result; +} + +} // namespace + +void TextFormatDecodeData::AddString(arc_i32 key, + const TProtoStringType& input_for_decode, + const TProtoStringType& desired_output) { + for (std::vector<DataEntry>::const_iterator i = entries_.begin(); + i != entries_.end(); ++i) { + Y_ABSL_CHECK(i->first != key) + << "error: duplicate key (" << key + << ") making TextFormat data, input: \"" << input_for_decode + << "\", desired: \"" << desired_output << "\"."; + } + + const TProtoStringType& data = TextFormatDecodeData::DecodeDataForString( + input_for_decode, desired_output); + entries_.push_back(DataEntry(key, data)); +} + +TProtoStringType TextFormatDecodeData::Data() const { + std::ostringstream data_stringstream; + + if (num_entries() > 0) { + io::OstreamOutputStream data_outputstream(&data_stringstream); + io::CodedOutputStream output_stream(&data_outputstream); + + output_stream.WriteVarint32(num_entries()); + for (std::vector<DataEntry>::const_iterator i = entries_.begin(); + i != entries_.end(); ++i) { + output_stream.WriteVarint32(i->first); + output_stream.WriteString(i->second); + } + } + + data_stringstream.flush(); + return data_stringstream.str(); +} + +// static +TProtoStringType TextFormatDecodeData::DecodeDataForString( + const TProtoStringType& input_for_decode, const TProtoStringType& desired_output) { + Y_ABSL_CHECK(!input_for_decode.empty() && !desired_output.empty()) + << "error: got empty string for making TextFormat data, input: \"" + << input_for_decode << "\", desired: \"" << desired_output << "\"."; + Y_ABSL_CHECK(!y_absl::StrContains(input_for_decode, '\0') && + !y_absl::StrContains(desired_output, '\0')) + << "error: got a null char in a string for making TextFormat data," + << " input: \"" << y_absl::CEscape(input_for_decode) << "\", desired: \"" + << y_absl::CEscape(desired_output) << "\"."; + + DecodeDataBuilder builder; + + // Walk the output building it from the input. + int x = 0; + for (int y = 0; y < desired_output.size(); y++) { + const char d = desired_output[y]; + if (d == '_') { + builder.AddUnderscore(); + continue; + } + + if (x >= input_for_decode.size()) { + // Out of input, no way to encode it, just return a full decode. + return DirectDecodeString(desired_output); + } + if (builder.AddCharacter(d, input_for_decode[x])) { + ++x; // Consumed one input + } else { + // Couldn't transform for the next character, just return a full decode. + return DirectDecodeString(desired_output); + } + } + + if (x != input_for_decode.size()) { + // Extra input (suffix from name sanitizing?), just return a full decode. + return DirectDecodeString(desired_output); + } + + // Add the end marker. + return builder.Finish() + (char)'\0'; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/text_format_decode_data.h b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/text_format_decode_data.h new file mode 100644 index 0000000000..135e4045b4 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/text_format_decode_data.h @@ -0,0 +1,83 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_TEXT_FORMAT_DECODE_DATA_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_TEXT_FORMAT_DECODE_DATA_H__ + +#include <string> +#include <utility> +#include <vector> + +#include "util/generic/string.h" + +// Must be included last +#include "google/protobuf/port_def.inc" + +using TProtoStringType = TString; + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// TODO(b/250947994): PROTOC_EXPORT is only used to allow the CMake build to +// find/link these in the unittest, this is not public api. + +// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform +// the input into the expected output. +class PROTOC_EXPORT TextFormatDecodeData { + public: + TextFormatDecodeData() = default; + ~TextFormatDecodeData() = default; + + TextFormatDecodeData(const TextFormatDecodeData&) = delete; + TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete; + + void AddString(arc_i32 key, const TProtoStringType& input_for_decode, + const TProtoStringType& desired_output); + size_t num_entries() const { return entries_.size(); } + TProtoStringType Data() const; + + static TProtoStringType DecodeDataForString(const TProtoStringType& input_for_decode, + const TProtoStringType& desired_output); + + private: + typedef std::pair<arc_i32, TProtoStringType> DataEntry; + std::vector<DataEntry> entries_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_TEXT_FORMAT_DECODE_DATA_H__ |