diff options
| author | thegeorg <[email protected]> | 2022-02-10 16:45:12 +0300 | 
|---|---|---|
| committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:45:12 +0300 | 
| commit | 49116032d905455a7b1c994e4a696afc885c1e71 (patch) | |
| tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.cc | |
| parent | 4e839db24a3bbc9f1c610c43d6faaaa99824dcca (diff) | |
Restoring authorship annotation for <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.cc')
| -rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.cc | 1220 | 
1 files changed, 610 insertions, 610 deletions
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 index f399d6e4bc1..63b543bfb45 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -1,610 +1,610 @@ -// 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_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 int32 GOOGLE_PROTOBUF_OBJC_VERSION = 30004;  -  -const char* kHeaderExtension = ".pbobjc.h";  -  -// 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;  -}  -  -// Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all  -// deps as visited and prunes them from the needed files list.  -void PruneFileAndDepsMarkingAsVisited(  -    const FileDescriptor* file,  -    std::vector<const FileDescriptor*>* files,  -    std::set<const FileDescriptor*>* files_visited) {  -  std::vector<const FileDescriptor*>::iterator iter =  -      std::find(files->begin(), files->end(), file);  -  if (iter != files->end()) {  -    files->erase(iter);  -  }  -  files_visited->insert(file);  -  for (int i = 0; i < file->dependency_count(); i++) {  -    PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited);  -  }  -}  -  -// Helper for CollectMinimalFileDepsContainingExtensions.  -void CollectMinimalFileDepsContainingExtensionsWorker(  -    const FileDescriptor* file,  -    std::vector<const FileDescriptor*>* files,  -    std::set<const FileDescriptor*>* files_visited) {  -  if (files_visited->find(file) != files_visited->end()) {  -    return;  -  }  -  files_visited->insert(file);  -  -  if (FileContainsExtensions(file)) {  -    files->push_back(file);  -    for (int i = 0; i < file->dependency_count(); i++) {  -      const FileDescriptor* dep = file->dependency(i);  -      PruneFileAndDepsMarkingAsVisited(dep, files, files_visited);  -    }  -  } else {  -    for (int i = 0; i < file->dependency_count(); i++) {  -      const FileDescriptor* dep = file->dependency(i);  -      CollectMinimalFileDepsContainingExtensionsWorker(dep, files,  -                                                       files_visited);  -    }  -  }  -}  -  -// 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).  -void CollectMinimalFileDepsContainingExtensions(  -    const FileDescriptor* file,  -    std::vector<const FileDescriptor*>* files) {  -  std::set<const FileDescriptor*> files_visited;  -  for (int i = 0; i < file->dependency_count(); i++) {  -    const FileDescriptor* dep = file->dependency(i);  -    CollectMinimalFileDepsContainingExtensionsWorker(dep, files,  -                                                     &files_visited);  -  }  -}  -  -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;  -}  -  -}  // namespace  -  -FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)  -    : file_(file),  -      root_class_name_(FileClassName(file)),  -      is_bundled_proto_(IsProtobufLibraryBundledProtoFile(file)),  -      options_(options) {  -  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), options_);  -    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");  -  } 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));  -  -  // #import any headers for "public imports" in the proto file.  -  {  -    ImportWriter import_writer(  -        options_.generate_for_named_framework,  -        options_.named_framework_to_proto_path_mappings_path,  -        options_.runtime_import_prefix,  -        is_bundled_proto_);  -    const TProtoStringType header_extension(kHeaderExtension);  -    for (int i = 0; i < file_->public_dependency_count(); i++) {  -      import_writer.AddFile(file_->public_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);  -  }  -  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");  -  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;  -  CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions);  -  -  {  -    ImportWriter import_writer(  -        options_.generate_for_named_framework,  -        options_.named_framework_to_proto_path_mappings_path,  -        options_.runtime_import_prefix,  -        is_bundled_proto_);  -    const TProtoStringType header_extension(kHeaderExtension);  -  -    // #import the header for this proto file.  -    import_writer.AddFile(file_, header_extension);  -  -    // #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());  -  ImportWriter::PrintRuntimeImports(  -      printer, headers_to_import, options_.runtime_import_prefix, true);  -  printer->Print("\n");  -}  -  -}  // namespace objectivec  -}  // namespace compiler  -}  // namespace protobuf  -}  // namespace google  +// 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_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 int32 GOOGLE_PROTOBUF_OBJC_VERSION = 30004; + +const char* kHeaderExtension = ".pbobjc.h"; + +// 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; +} + +// Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all +// deps as visited and prunes them from the needed files list. +void PruneFileAndDepsMarkingAsVisited( +    const FileDescriptor* file, +    std::vector<const FileDescriptor*>* files, +    std::set<const FileDescriptor*>* files_visited) { +  std::vector<const FileDescriptor*>::iterator iter = +      std::find(files->begin(), files->end(), file); +  if (iter != files->end()) { +    files->erase(iter); +  } +  files_visited->insert(file); +  for (int i = 0; i < file->dependency_count(); i++) { +    PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited); +  } +} + +// Helper for CollectMinimalFileDepsContainingExtensions. +void CollectMinimalFileDepsContainingExtensionsWorker( +    const FileDescriptor* file, +    std::vector<const FileDescriptor*>* files, +    std::set<const FileDescriptor*>* files_visited) { +  if (files_visited->find(file) != files_visited->end()) { +    return; +  } +  files_visited->insert(file); + +  if (FileContainsExtensions(file)) { +    files->push_back(file); +    for (int i = 0; i < file->dependency_count(); i++) { +      const FileDescriptor* dep = file->dependency(i); +      PruneFileAndDepsMarkingAsVisited(dep, files, files_visited); +    } +  } else { +    for (int i = 0; i < file->dependency_count(); i++) { +      const FileDescriptor* dep = file->dependency(i); +      CollectMinimalFileDepsContainingExtensionsWorker(dep, files, +                                                       files_visited); +    } +  } +} + +// 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). +void CollectMinimalFileDepsContainingExtensions( +    const FileDescriptor* file, +    std::vector<const FileDescriptor*>* files) { +  std::set<const FileDescriptor*> files_visited; +  for (int i = 0; i < file->dependency_count(); i++) { +    const FileDescriptor* dep = file->dependency(i); +    CollectMinimalFileDepsContainingExtensionsWorker(dep, files, +                                                     &files_visited); +  } +} + +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; +} + +}  // namespace + +FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) +    : file_(file), +      root_class_name_(FileClassName(file)), +      is_bundled_proto_(IsProtobufLibraryBundledProtoFile(file)), +      options_(options) { +  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), options_); +    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"); +  } 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)); + +  // #import any headers for "public imports" in the proto file. +  { +    ImportWriter import_writer( +        options_.generate_for_named_framework, +        options_.named_framework_to_proto_path_mappings_path, +        options_.runtime_import_prefix, +        is_bundled_proto_); +    const TProtoStringType header_extension(kHeaderExtension); +    for (int i = 0; i < file_->public_dependency_count(); i++) { +      import_writer.AddFile(file_->public_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); +  } +  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"); +  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; +  CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions); + +  { +    ImportWriter import_writer( +        options_.generate_for_named_framework, +        options_.named_framework_to_proto_path_mappings_path, +        options_.runtime_import_prefix, +        is_bundled_proto_); +    const TProtoStringType header_extension(kHeaderExtension); + +    // #import the header for this proto file. +    import_writer.AddFile(file_, header_extension); + +    // #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()); +  ImportWriter::PrintRuntimeImports( +      printer, headers_to_import, options_.runtime_import_prefix, true); +  printer->Print("\n"); +} + +}  // namespace objectivec +}  // namespace compiler +}  // namespace protobuf +}  // namespace google  | 
