diff options
Diffstat (limited to 'src')
23 files changed, 647 insertions, 189 deletions
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index e6c3b36a..0de7e2c6 100755 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -134,12 +134,51 @@ bool IsReserved(const string& ident) { // Returns a copy of |filename| with any trailing ".protodevel" or ".proto // suffix stripped. +// TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc. string StripProto(const string& filename) { const char* suffix = HasSuffixString(filename, ".protodevel") ? ".protodevel" : ".proto"; return StripSuffixString(filename, suffix); } +// Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript +// file foo/bar/baz.js. +string GetJSFilename(const string& filename) { + const char* suffix = HasSuffixString(filename, ".protodevel") + ? ".protodevel" : ".proto"; + return StripSuffixString(filename, suffix) + "_pb.js"; +} + +// Given a filename like foo/bar/baz.proto, returns the root directory +// path ../../ +string GetRootPath(const string& filename) { + size_t slashes = std::count(filename.begin(), filename.end(), '/'); + if (slashes == 0) { + return "./"; + } + string result = ""; + for (size_t i = 0; i < slashes; i++) { + result += "../"; + } + return result; +} + +// Returns the alias we assign to the module of the given .proto filename +// when importing. +string ModuleAlias(const string& filename) { + // This scheme could technically cause problems if a file includes any 2 of: + // foo/bar_baz.proto + // foo_bar_baz.proto + // foo_bar/baz.proto + // + // We'll worry about this problem if/when we actually see it. This name isn't + // exposed to users so we can change it later if we need to. + string basename = StripProto(filename); + StripString(&basename, "-", '$'); + StripString(&basename, "/", '_'); + return basename + "_pb"; +} + // Returns the fully normalized JavaScript path for the given // file descriptor's package. string GetPath(const GeneratorOptions& options, @@ -215,6 +254,26 @@ string GetPath(const GeneratorOptions& options, value_descriptor->type()) + "." + value_descriptor->name(); } +string MaybeCrossFileRef(const GeneratorOptions& options, + const FileDescriptor* from_file, + const Descriptor* to_message) { + if (options.import_style == GeneratorOptions::IMPORT_COMMONJS && + from_file != to_message->file()) { + // Cross-file ref in CommonJS needs to use the module alias instead of + // the global name. + return ModuleAlias(to_message->file()->name()) + "." + to_message->name(); + } else { + // Within a single file we use a full name. + return GetPath(options, to_message); + } +} + +string SubmessageTypeRef(const GeneratorOptions& options, + const FieldDescriptor* field) { + GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); + return MaybeCrossFileRef(options, field->file(), field->message_type()); +} + // - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields // (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate, // and with reserved words triggering a "pb_" prefix. @@ -952,11 +1011,13 @@ string RelativeTypeName(const FieldDescriptor* field) { } string JSExtensionsObjectName(const GeneratorOptions& options, + const FileDescriptor* from_file, const Descriptor* desc) { if (desc->full_name() == "google.protobuf.bridge.MessageSet") { + // TODO(haberman): fix this for the IMPORT_COMMONJS case. return "jspb.Message.messageSetExtensions"; } else { - return GetPath(options, desc) + ".extensions"; + return MaybeCrossFileRef(options, from_file, desc) + ".extensions"; } } @@ -1113,19 +1174,24 @@ void Generator::GenerateHeader(const GeneratorOptions& options, "\n"); } +void Generator::FindProvidesForFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file, + std::set<string>* provided) const { + for (int i = 0; i < file->message_type_count(); i++) { + FindProvidesForMessage(options, printer, file->message_type(i), provided); + } + for (int i = 0; i < file->enum_type_count(); i++) { + FindProvidesForEnum(options, printer, file->enum_type(i), provided); + } +} + void Generator::FindProvides(const GeneratorOptions& options, io::Printer* printer, const vector<const FileDescriptor*>& files, std::set<string>* provided) const { for (int i = 0; i < files.size(); i++) { - for (int j = 0; j < files[i]->message_type_count(); j++) { - FindProvidesForMessage(options, printer, files[i]->message_type(j), - provided); - } - for (int j = 0; j < files[i]->enum_type_count(); j++) { - FindProvidesForEnum(options, printer, files[i]->enum_type(j), - provided); - } + FindProvidesForFile(options, printer, files[i], provided); } printer->Print("\n"); @@ -1204,38 +1270,45 @@ void Generator::GenerateRequires(const GeneratorOptions& options, io::Printer* printer, const vector<const FileDescriptor*>& files, std::set<string>* provided) const { - std::set<string> required; - std::set<string> forwards; - bool have_extensions = false; - bool have_message = false; - - for (int i = 0; i < files.size(); i++) { - for (int j = 0; j < files[i]->message_type_count(); j++) { - FindRequiresForMessage(options, - files[i]->message_type(j), - &required, &forwards, &have_message); - } - if (!have_extensions && HasExtensions(files[i])) { - have_extensions = true; - } + if (options.import_style == GeneratorOptions::IMPORT_BROWSER) { + return; + } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { + // For Closure imports we need to import every message type individually. + std::set<string> required; + std::set<string> forwards; + bool have_extensions = false; + bool have_message = false; - for (int j = 0; j < files[i]->extension_count(); j++) { - const FieldDescriptor* extension = files[i]->extension(j); - if (IgnoreField(extension)) { - continue; + for (int i = 0; i < files.size(); i++) { + for (int j = 0; j < files[i]->message_type_count(); j++) { + FindRequiresForMessage(options, + files[i]->message_type(j), + &required, &forwards, &have_message); } - if (extension->containing_type()->full_name() != - "google.protobuf.bridge.MessageSet") { - required.insert(GetPath(options, extension->containing_type())); + if (!have_extensions && HasExtensions(files[i])) { + have_extensions = true; + } + + for (int j = 0; j < files[i]->extension_count(); j++) { + const FieldDescriptor* extension = files[i]->extension(j); + if (IgnoreField(extension)) { + continue; + } + if (extension->containing_type()->full_name() != + "google.protobuf.bridge.MessageSet") { + required.insert(GetPath(options, extension->containing_type())); + } + FindRequiresForField(options, extension, &required, &forwards); + have_extensions = true; } - FindRequiresForField(options, extension, &required, &forwards); - have_extensions = true; } - } - GenerateRequiresImpl(options, printer, &required, &forwards, provided, - /* require_jspb = */ have_message, - /* require_extension = */ have_extensions); + GenerateRequiresImpl(options, printer, &required, &forwards, provided, + /* require_jspb = */ have_message, + /* require_extension = */ have_extensions); + } else if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { + // CommonJS imports are based on files + } } void Generator::GenerateRequires(const GeneratorOptions& options, @@ -1406,6 +1479,12 @@ void Generator::GenerateClass(const GeneratorOptions& options, if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") { GenerateClassExtensionFieldInfo(options, printer, desc); } + + if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) { + for (int i = 0; i < desc->extension_count(); i++) { + GenerateExtension(options, printer, desc->extension(i)); + } + } } // Recurse on nested types. @@ -1623,7 +1702,7 @@ void Generator::GenerateClassToObject(const GeneratorOptions& options, "obj,\n" " $extObject$, $class$.prototype.getExtension,\n" " includeInstance);\n", - "extObject", JSExtensionsObjectName(options, desc), + "extObject", JSExtensionsObjectName(options, desc->file(), desc), "class", GetPath(options, desc)); } @@ -1652,13 +1731,13 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n" " $type$.toObject, includeInstance)", "getter", JSGetterName(field), - "type", GetPath(options, field->message_type())); + "type", SubmessageTypeRef(options, field)); } } else { printer->Print("(f = msg.get$getter$()) && " "$type$.toObject(includeInstance, f)", "getter", JSGetterName(field), - "type", GetPath(options, field->message_type())); + "type", SubmessageTypeRef(options, field)); } } else { // Simple field (singular or repeated). @@ -1723,7 +1802,7 @@ void Generator::GenerateClassFieldFromObject( " }));\n", "name", JSObjectFieldName(field), "index", JSFieldIndex(field), - "fieldclass", GetPath(options, field->message_type())); + "fieldclass", SubmessageTypeRef(options, field)); } } else { printer->Print( @@ -1731,7 +1810,7 @@ void Generator::GenerateClassFieldFromObject( " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n", "name", JSObjectFieldName(field), "index", JSFieldIndex(field), - "fieldclass", GetPath(options, field->message_type())); + "fieldclass", SubmessageTypeRef(options, field)); } } else { // Simple (primitive) field. @@ -1815,7 +1894,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, /* always_singular = */ false), "rpt", (field->is_repeated() ? "Repeated" : ""), "index", JSFieldIndex(field), - "wrapperclass", GetPath(options, field->message_type()), + "wrapperclass", SubmessageTypeRef(options, field), "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? ", 1" : "")); printer->Print( @@ -2043,7 +2122,7 @@ void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options, " $class$.prototype.getExtension,\n" " $class$.prototype.setExtension);\n" " break;\n", - "extobj", JSExtensionsObjectName(options, desc), + "extobj", JSExtensionsObjectName(options, desc->file(), desc), "class", GetPath(options, desc)); } else { printer->Print( @@ -2073,7 +2152,7 @@ void Generator::GenerateClassDeserializeBinaryField( " var value = new $fieldclass$;\n" " reader.read$msgOrGroup$($grpfield$value," "$fieldclass$.deserializeBinaryFromReader);\n", - "fieldclass", GetPath(options, field->message_type()), + "fieldclass", SubmessageTypeRef(options, field), "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message", "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ? @@ -2149,7 +2228,7 @@ void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options, printer->Print( " jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n" " $class$.prototype.getExtension);\n", - "extobj", JSExtensionsObjectName(options, desc), + "extobj", JSExtensionsObjectName(options, desc->file(), desc), "class", GetPath(options, desc)); } @@ -2222,7 +2301,7 @@ void Generator::GenerateClassSerializeBinaryField( printer->Print( ",\n" " $submsg$.serializeBinaryToWriter\n", - "submsg", GetPath(options, field->message_type())); + "submsg", SubmessageTypeRef(options, field)); } else { printer->Print("\n"); } @@ -2290,9 +2369,9 @@ void Generator::GenerateExtension(const GeneratorOptions& options, "index", SimpleItoa(field->number()), "name", JSObjectFieldName(field), "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? - GetPath(options, field->message_type()) : string("null")), + SubmessageTypeRef(options, field) : string("null")), "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? - (GetPath(options, field->message_type()) + ".toObject") : + (SubmessageTypeRef(options, field) + ".toObject") : string("null")), "repeated", (field->is_repeated() ? "1" : "0")); @@ -2308,11 +2387,11 @@ void Generator::GenerateExtension(const GeneratorOptions& options, "binaryWriterFn", JSBinaryWriterMethodName(field), "binaryMessageSerializeFn", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? - (GetPath(options, field->message_type()) + + (SubmessageTypeRef(options, field) + ".serializeBinaryToWriter") : "null", "binaryMessageDeserializeFn", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? - (GetPath(options, field->message_type()) + + (SubmessageTypeRef(options, field) + ".deserializeBinaryFromReader") : "null", "isPacked", (field->is_packed() ? "true" : "false")); } else { @@ -2324,7 +2403,8 @@ void Generator::GenerateExtension(const GeneratorOptions& options, "// toObject() will function correctly.\n" "$extendName$[$index$] = $class$.$name$;\n" "\n", - "extendName", JSExtensionsObjectName(options, field->containing_type()), + "extendName", JSExtensionsObjectName(options, field->file(), + field->containing_type()), "index", SimpleItoa(field->number()), "class", extension_scope, "name", JSObjectFieldName(field)); @@ -2364,6 +2444,19 @@ bool GeneratorOptions::ParseFromOptions( namespace_prefix = options[i].second; } else if (options[i].first == "library") { library = options[i].second; + } else if (options[i].first == "import_style") { + if (options[i].second == "closure") { + import_style = IMPORT_CLOSURE; + } else if (options[i].second == "commonjs") { + import_style = IMPORT_COMMONJS; + } else if (options[i].second == "browser") { + import_style = IMPORT_BROWSER; + } else if (options[i].second == "es6") { + import_style = IMPORT_ES6; + } else { + *error = "Unknown import style " + options[i].second + ", expected " + + "one of: closure, commonjs, browser, es6."; + } } else { // Assume any other option is an output directory, as long as it is a bare // `key` rather than a `key=value` option. @@ -2375,6 +2468,11 @@ bool GeneratorOptions::ParseFromOptions( } } + if (!library.empty() && import_style != IMPORT_CLOSURE) { + *error = "The library option should only be used for " + "import_style=closure"; + } + return true; } @@ -2418,6 +2516,63 @@ void Generator::GenerateFileAndDeps( } } +void Generator::GenerateFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const { + GenerateHeader(options, printer); + + // Generate "require" statements. + if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { + printer->Print("var jspb = require('google-protobuf');\n"); + printer->Print("var goog = jspb;\n"); + printer->Print("var global = Function('return this')();\n\n"); + + for (int i = 0; i < file->dependency_count(); i++) { + const std::string& name = file->dependency(i)->name(); + printer->Print( + "var $alias$ = require('$file$');\n", + "alias", ModuleAlias(name), + "file", GetRootPath(file->name()) + GetJSFilename(name)); + } + } + + // We aren't using Closure's import system, but we use goog.exportSymbol() + // to construct the expected tree of objects, eg. + // + // goog.exportSymbol('foo.bar.Baz', null, this); + // + // // Later generated code expects foo.bar = {} to exist: + // foo.bar.Baz = function() { /* ... */ } + std::set<std::string> provided; + + // Cover the case where this file declares extensions but no messages. + // This will ensure that the file-level object will be declared to hold + // the extensions. + for (int i = 0; i < file->extension_count(); i++) { + provided.insert(file->extension(i)->full_name()); + } + + FindProvidesForFile(options, printer, file, &provided); + for (std::set<string>::iterator it = provided.begin(); + it != provided.end(); ++it) { + printer->Print("goog.exportSymbol('$name$', null, global);\n", + "name", *it); + } + + GenerateClassesAndEnums(options, printer, file); + + // Extensions nested inside messages are emitted inside + // GenerateClassesAndEnums(). + for (int i = 0; i < file->extension_count(); i++) { + GenerateExtension(options, printer, file->extension(i)); + } + + if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { + printer->Print("goog.object.extend(exports, $package$);\n", + "package", GetPath(options, file)); + } +} + bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, const string& parameter, GeneratorContext* context, @@ -2430,10 +2585,14 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, } - // We're either generating a single library file with definitions for message - // and enum types in *all* FileDescriptor inputs, or we're generating a single - // file for each type. - if (options.library != "") { + // There are three schemes for where output files go: + // + // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file + // - import_style = IMPORT_CLOSURE, library empty: one output file per type + // - import_style != IMPORT_CLOSURE: one output file per .proto file + if (options.import_style == GeneratorOptions::IMPORT_CLOSURE && + options.library != "") { + // All output should go in a single file. string filename = options.output_dir + "/" + options.library + ".js"; google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); GOOGLE_CHECK(output.get()); @@ -2469,7 +2628,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, if (printer.failed()) { return false; } - } else { + } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { // Collect all types, and print each type to a separate file. Pull out // free-floating extensions while we make this pass. map< string, vector<const FieldDescriptor*> > extensions_by_namespace; @@ -2611,6 +2770,24 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, } } } + } else { + // Generate one output file per input (.proto) file. + + for (int i = 0; i < files.size(); i++) { + const google::protobuf::FileDescriptor* file = files[i]; + + string filename = options.output_dir + "/" + GetJSFilename(file->name()); + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + context->Open(filename)); + GOOGLE_CHECK(output.get()); + io::Printer printer(output.get(), '$'); + + GenerateFile(options, &printer, file); + + if (printer.failed()) { + return false; + } + } } return true; diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h index db2dceb3..db9178d3 100755 --- a/src/google/protobuf/compiler/js/js_generator.h +++ b/src/google/protobuf/compiler/js/js_generator.h @@ -67,6 +67,13 @@ struct GeneratorOptions { bool error_on_name_conflict; // Enable binary-format support? bool binary; + // What style of imports should be used. + enum ImportStyle { + IMPORT_CLOSURE, // goog.require() + IMPORT_COMMONJS, // require() + IMPORT_BROWSER, // no import statements + IMPORT_ES6, // import { member } from '' + } import_style; GeneratorOptions() : add_require_for_enums(false), @@ -75,7 +82,8 @@ struct GeneratorOptions { namespace_prefix(""), library(""), error_on_name_conflict(false), - binary(false) {} + binary(false), + import_style(IMPORT_CLOSURE) {} bool ParseFromOptions( const vector< pair< string, string > >& options, @@ -111,6 +119,10 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { io::Printer* printer, const vector<const FileDescriptor*>& file, std::set<string>* provided) const; + void FindProvidesForFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file, + std::set<string>* provided) const; void FindProvidesForMessage(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc, @@ -168,6 +180,10 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { std::set<string>* required, std::set<string>* forwards) const; + void GenerateFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const; + // Generate definitions for all message classes and enums in all files, // processing the files in dependence order. void GenerateFilesInDepOrder(const GeneratorOptions& options, diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 97df536e..66ad13b7 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -78,7 +78,7 @@ int main(int argc, char* argv[]) { // Objective C google::protobuf::compiler::objectivec::ObjectiveCGenerator objc_generator; - cli.RegisterGenerator("--objc_out", &objc_generator, + cli.RegisterGenerator("--objc_out", "--objc_opt", &objc_generator, "Generate Objective C header and source."); // JavaScript diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc index 30a13ddb..ecc77f6b 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc @@ -44,6 +44,7 @@ namespace compiler { namespace objectivec { namespace { + void SetEnumVariables(const FieldDescriptor* descriptor, map<string, string>* variables) { string type = EnumName(descriptor->enum_type()); @@ -63,8 +64,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor, } } // namespace -EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor) - : SingleFieldGenerator(descriptor) { +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : SingleFieldGenerator(descriptor, options) { SetEnumVariables(descriptor, &variables_); } @@ -112,6 +114,7 @@ void EnumFieldGenerator::GenerateCFunctionImplementations( void EnumFieldGenerator::DetermineForwardDeclarations( set<string>* fwd_decls) const { + SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls); // If it is an enum defined in a different file, 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. @@ -123,14 +126,20 @@ void EnumFieldGenerator::DetermineForwardDeclarations( } RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( - const FieldDescriptor* descriptor) - : RepeatedFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { SetEnumVariables(descriptor, &variables_); variables_["array_storage_type"] = "GPBEnumArray"; } RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} +void RepeatedEnumFieldGenerator::FinishInitialization(void) { + RepeatedFieldGenerator::FinishInitialization(); + variables_["array_comment"] = + "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; +} + void RepeatedEnumFieldGenerator::GenerateFieldDescriptionTypeSpecific( io::Printer* printer) const { printer->Print( diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h index b629eae8..ae2f57e3 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h @@ -41,7 +41,8 @@ namespace compiler { namespace objectivec { class EnumFieldGenerator : public SingleFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); public: virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; @@ -50,7 +51,7 @@ class EnumFieldGenerator : public SingleFieldGenerator { virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; protected: - explicit EnumFieldGenerator(const FieldDescriptor* descriptor); + EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); virtual ~EnumFieldGenerator(); private: @@ -58,13 +59,16 @@ class EnumFieldGenerator : public SingleFieldGenerator { }; class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); public: + virtual void FinishInitialization(); virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; protected: - RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor); + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~RepeatedEnumFieldGenerator(); private: diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc index cf5d8cfb..09341820 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -45,6 +45,7 @@ namespace compiler { namespace objectivec { namespace { + void SetCommonFieldVariables(const FieldDescriptor* descriptor, map<string, string>* variables) { string camel_case_name = FieldName(descriptor); @@ -117,39 +118,40 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, } // namespace -FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) { +FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options) { FieldGenerator* result = NULL; if (field->is_repeated()) { switch (GetObjectiveCType(field)) { case OBJECTIVECTYPE_MESSAGE: { if (field->is_map()) { - result = new MapFieldGenerator(field); + result = new MapFieldGenerator(field, options); } else { - result = new RepeatedMessageFieldGenerator(field); + result = new RepeatedMessageFieldGenerator(field, options); } break; } case OBJECTIVECTYPE_ENUM: - result = new RepeatedEnumFieldGenerator(field); + result = new RepeatedEnumFieldGenerator(field, options); break; default: - result = new RepeatedPrimitiveFieldGenerator(field); + result = new RepeatedPrimitiveFieldGenerator(field, options); break; } } else { switch (GetObjectiveCType(field)) { case OBJECTIVECTYPE_MESSAGE: { - result = new MessageFieldGenerator(field); + result = new MessageFieldGenerator(field, options); break; } case OBJECTIVECTYPE_ENUM: - result = new EnumFieldGenerator(field); + result = new EnumFieldGenerator(field, options); break; default: if (IsReferenceType(field)) { - result = new PrimitiveObjFieldGenerator(field); + result = new PrimitiveObjFieldGenerator(field, options); } else { - result = new PrimitiveFieldGenerator(field); + result = new PrimitiveFieldGenerator(field, options); } break; } @@ -158,8 +160,8 @@ FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) { return result; } - -FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor) +FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { SetCommonFieldVariables(descriptor, &variables_); } @@ -252,9 +254,9 @@ void FieldGenerator::FinishInitialization(void) { } } -SingleFieldGenerator::SingleFieldGenerator( - const FieldDescriptor* descriptor) - : FieldGenerator(descriptor) { +SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(descriptor, options) { // Nothing } @@ -300,9 +302,9 @@ bool SingleFieldGenerator::WantsHasProperty(void) const { return false; } -ObjCObjFieldGenerator::ObjCObjFieldGenerator( - const FieldDescriptor* descriptor) - : SingleFieldGenerator(descriptor) { +ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : SingleFieldGenerator(descriptor, options) { variables_["property_storage_attribute"] = "strong"; if (IsRetainedName(variables_["name"])) { variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED"; @@ -342,18 +344,21 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration( } RepeatedFieldGenerator::RepeatedFieldGenerator( - const FieldDescriptor* descriptor) - : ObjCObjFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { // Repeated fields don't use the has index. variables_["has_index"] = "GPBNoHasBit"; + // Default to no comment and let the cases needing it fill it in. + variables_["array_comment"] = ""; } RepeatedFieldGenerator::~RepeatedFieldGenerator() {} void RepeatedFieldGenerator::FinishInitialization(void) { FieldGenerator::FinishInitialization(); - variables_["array_comment"] = - "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; + if (variables_.find("array_property_type") == variables_.end()) { + variables_["array_property_type"] = variable("array_storage_type"); + } } void RepeatedFieldGenerator::GenerateFieldStorageDeclaration( @@ -379,13 +384,13 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration( variables_, "$comments$" "$array_comment$" - "@property(nonatomic, readwrite, strong, null_resettable) $array_storage_type$ *$name$$storage_attribute$;\n" + "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$;\n" "@property(nonatomic, readonly) NSUInteger $name$_Count;\n"); 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_, - "- ($array_storage_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); + "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); } printer->Print("\n"); } @@ -395,7 +400,8 @@ bool RepeatedFieldGenerator::WantsHasProperty(void) const { return false; } -FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, + const Options& options) : descriptor_(descriptor), field_generators_( new scoped_ptr<FieldGenerator>[descriptor->field_count()]), @@ -403,10 +409,12 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) new scoped_ptr<FieldGenerator>[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), options)); } for (int i = 0; i < descriptor->extension_count(); i++) { - extension_generators_[i].reset(FieldGenerator::Make(descriptor->extension(i))); + extension_generators_[i].reset( + FieldGenerator::Make(descriptor->extension(i), options)); } } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h index 130a52dd..e8a20a72 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h @@ -49,24 +49,31 @@ namespace objectivec { class FieldGenerator { public: - static FieldGenerator* Make(const FieldDescriptor* field); + static FieldGenerator* Make(const FieldDescriptor* field, + const Options& options); virtual ~FieldGenerator(); + // Exposed for subclasses to fill in. virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0; virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0; - virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0; - virtual void GenerateFieldDescription(io::Printer* printer) const; + // Called by GenerateFieldDescription, exposed for classes that need custom + // generation. virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; - virtual void GenerateFieldNumberConstant(io::Printer* printer) const; + // Exposed for subclasses to extend, base does nothing. virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; virtual void GenerateCFunctionImplementations(io::Printer* printer) const; + // Exposed for subclasses, should always call it on the parent class also. virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; + // Used during generation, not intended to be extended by subclasses. + void GenerateFieldDescription(io::Printer* printer) const; + void GenerateFieldNumberConstant(io::Printer* printer) const; + void SetOneofIndexBase(int index_base); string variable(const char* key) const { @@ -81,7 +88,7 @@ class FieldGenerator { string raw_field_name() const { return variable("raw_field_name"); } protected: - explicit FieldGenerator(const FieldDescriptor* descriptor); + FieldGenerator(const FieldDescriptor* descriptor, const Options& options); virtual void FinishInitialization(void); virtual bool WantsHasProperty(void) const = 0; @@ -103,7 +110,8 @@ class SingleFieldGenerator : public FieldGenerator { virtual void GeneratePropertyImplementation(io::Printer* printer) const; protected: - explicit SingleFieldGenerator(const FieldDescriptor* descriptor); + SingleFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual bool WantsHasProperty(void) const; private: @@ -119,7 +127,8 @@ class ObjCObjFieldGenerator : public SingleFieldGenerator { virtual void GeneratePropertyDeclaration(io::Printer* printer) const; protected: - explicit ObjCObjFieldGenerator(const FieldDescriptor* descriptor); + ObjCObjFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjCObjFieldGenerator); @@ -135,7 +144,8 @@ class RepeatedFieldGenerator : public ObjCObjFieldGenerator { virtual void GeneratePropertyImplementation(io::Printer* printer) const; protected: - explicit RepeatedFieldGenerator(const FieldDescriptor* descriptor); + RepeatedFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual void FinishInitialization(void); virtual bool WantsHasProperty(void) const; @@ -146,7 +156,7 @@ class RepeatedFieldGenerator : public ObjCObjFieldGenerator { // Convenience class which constructs FieldGenerators for a Descriptor. class FieldGeneratorMap { public: - explicit FieldGeneratorMap(const Descriptor* descriptor); + FieldGeneratorMap(const Descriptor* descriptor, const Options& options); ~FieldGeneratorMap(); const FieldGenerator& get(const FieldDescriptor* field) const; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index 228c66f0..cdf9ebbc 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -50,17 +50,18 @@ const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30000; namespace compiler { namespace objectivec { -FileGenerator::FileGenerator(const FileDescriptor *file) +FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options) : file_(file), root_class_name_(FileClassName(file)), - is_public_dep_(false) { + is_public_dep_(false), + options_(options) { for (int i = 0; i < file_->enum_type_count(); i++) { EnumGenerator *generator = new EnumGenerator(file_->enum_type(i)); enum_generators_.push_back(generator); } for (int i = 0; i < file_->message_type_count(); i++) { MessageGenerator *generator = - new MessageGenerator(root_class_name_, file_->message_type(i)); + new MessageGenerator(root_class_name_, file_->message_type(i), options_); message_generators_.push_back(generator); } for (int i = 0; i < file_->extension_count(); i++) { @@ -352,7 +353,8 @@ const vector<FileGenerator *> &FileGenerator::DependencyGenerators() { public_import_names.insert(file_->public_dependency(i)->name()); } for (int i = 0; i < file_->dependency_count(); i++) { - FileGenerator *generator = new FileGenerator(file_->dependency(i)); + FileGenerator *generator = + new FileGenerator(file_->dependency(i), options_); const string& name = file_->dependency(i)->name(); bool public_import = (public_import_names.count(name) != 0); generator->SetIsPublicDependency(public_import); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h index 1bb4f0ea..4c0fcd3f 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h @@ -55,7 +55,7 @@ class MessageGenerator; class FileGenerator { public: - explicit FileGenerator(const FileDescriptor* file); + FileGenerator(const FileDescriptor* file, const Options& options); ~FileGenerator(); void GenerateSource(io::Printer* printer); @@ -84,6 +84,8 @@ class FileGenerator { vector<ExtensionGenerator*> extension_generators_; bool is_public_dep_; + const Options options_; + const vector<FileGenerator*>& DependencyGenerators(); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc index 375b4e0f..72e295de 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc @@ -49,21 +49,31 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file, const string& parameter, OutputDirectory* output_directory, string* error) const { - // ObjC doesn't have any options at the moment, error if passed one. + // ----------------------------------------------------------------- + // Parse generator options. + + Options generation_options; + vector<pair<string, string> > options; ParseGeneratorParameter(parameter, &options); for (int i = 0; i < options.size(); i++) { - *error = "error:: Unknown generator option: " + options[i].first; - return false; + if (options[i].first == "expected_prefixes_path") { + generation_options.expected_prefixes_path = options[i].second; + } else { + *error = "error: Unknown generator option: " + options[i].first; + return false; + } } + // ----------------------------------------------------------------- + // Validate the objc prefix/package pairing. - if (!ValidateObjCClassPrefix(file, error)) { + if (!ValidateObjCClassPrefix(file, generation_options, error)) { // *error will have been filled in. return false; } - FileGenerator file_generator(file); + FileGenerator file_generator(file, generation_options); string filepath = FilePath(file); // Generate header. diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index 8527b74b..77a378c8 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -58,6 +58,14 @@ namespace protobuf { namespace compiler { namespace objectivec { +Options::Options() { + // Default is the value of the env for the package prefixes. + const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); + if (file_path) { + expected_prefixes_path = file_path; + } +} + namespace { hash_set<string> MakeWordsMap(const char* const words[], size_t num_words) { @@ -890,26 +898,26 @@ bool Parser::ParseLoop() { return true; } -bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, - string* out_expect_file_path, +bool LoadExpectedPackagePrefixes(const Options &generation_options, + map<string, string>* prefix_map, string* out_error) { - const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); - if (file_path == NULL) { + if (generation_options.expected_prefixes_path.empty()) { return true; } int fd; do { - fd = open(file_path, O_RDONLY); + fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY); } while (fd < 0 && errno == EINTR); if (fd < 0) { *out_error = - string(file_path) + ":0:0: error: Unable to open." + strerror(errno); + string("error: Unable to open \"") + + generation_options.expected_prefixes_path + + "\", " + strerror(errno); return false; } io::FileInputStream file_stream(fd); file_stream.SetCloseOnDelete(true); - *out_expect_file_path = file_path; Parser parser(prefix_map); const void* buf; @@ -920,8 +928,9 @@ bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, } if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) { - *out_error = string(file_path) + ":" + SimpleItoa(parser.last_line()) + - ":0: error: " + parser.error_str(); + *out_error = + string("error: ") + generation_options.expected_prefixes_path + + " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str(); return false; } } @@ -930,7 +939,9 @@ bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, } // namespace -bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { +bool ValidateObjCClassPrefix(const FileDescriptor* file, + const Options& generation_options, + string* out_error) { const string prefix = file->options().objc_class_prefix(); const string package = file->package(); @@ -939,11 +950,10 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { // Load any expected package prefixes to validate against those. map<string, string> expected_package_prefixes; - string expect_file_path; - if (!LoadExpectedPackagePrefixes(&expected_package_prefixes, - &expect_file_path, out_error)) { - // Any error, clear the entries that were read. - expected_package_prefixes.clear(); + if (!LoadExpectedPackagePrefixes(generation_options, + &expected_package_prefixes, + out_error)) { + return false; } // Check: Error - See if there was an expected prefix for the package and @@ -957,7 +967,7 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { return true; } else { // ...it didn't match! - *out_error = "protoc:0: error: Expected 'option objc_class_prefix = \"" + + *out_error = "error: Expected 'option objc_class_prefix = \"" + package_match->second + "\";' in '" + file->name() + "'"; if (prefix.length()) { *out_error += "; but found '" + prefix + "' instead"; @@ -980,11 +990,11 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { i != expected_package_prefixes.end(); ++i) { if (i->second == prefix) { *out_error = - "protoc:0: error: Found 'option objc_class_prefix = \"" + prefix + + "error: Found 'option objc_class_prefix = \"" + prefix + "\";' in '" + file->name() + "'; that prefix is already used for 'package " + i->first + ";'. It can only be reused by listing it in the expected file (" + - expect_file_path + ")."; + generation_options.expected_prefixes_path + ")."; return false; // Only report first usage of the prefix. } } @@ -1017,7 +1027,7 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" << prefix << "\";' in '" << file->name() << "';" << " consider adding it to the expected prefixes file (" - << expect_file_path << ")." << endl; + << generation_options.expected_prefixes_path << ")." << endl; cerr.flush(); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index 85744862..5b2dd190 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -42,6 +42,12 @@ namespace protobuf { namespace compiler { namespace objectivec { +// Generator options (see objectivec_generator.cc for a description of each): +struct Options { + Options(); + string expected_prefixes_path; +}; + // Strips ".proto" or ".protodevel" from the end of a filename. string StripProto(const string& filename); @@ -145,7 +151,9 @@ string BuildCommentsString(const SourceLocation& location); // Checks the prefix for a given file and outputs any warnings needed, if // there are flat out errors, then out_error is filled in and the result is // false. -bool ValidateObjCClassPrefix(const FileDescriptor* file, string *out_error); +bool ValidateObjCClassPrefix(const FileDescriptor* file, + const Options& generation_options, + string* out_error); // Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform // the input into the expected output. diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc index 2987f3db..2751e936 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -84,13 +84,14 @@ const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) { } // namespace -MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) - : RepeatedFieldGenerator(descriptor) { +MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : RepeatedFieldGenerator(descriptor, options) { const FieldDescriptor* key_descriptor = descriptor->message_type()->FindFieldByName("key"); const FieldDescriptor* value_descriptor = descriptor->message_type()->FindFieldByName("value"); - value_field_generator_.reset(FieldGenerator::Make(value_descriptor)); + value_field_generator_.reset(FieldGenerator::Make(value_descriptor, options)); // Pull over some variables_ from the value. variables_["field_type"] = value_field_generator_->variable("field_type"); @@ -117,16 +118,27 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) variables_["fieldflags"] = BuildFlagsString(field_flags); ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); - if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) && + const bool value_is_object_type = ((value_objc_type == OBJECTIVECTYPE_STRING) || (value_objc_type == OBJECTIVECTYPE_DATA) || - (value_objc_type == OBJECTIVECTYPE_MESSAGE))) { + (value_objc_type == OBJECTIVECTYPE_MESSAGE)); + if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) && + value_is_object_type) { variables_["array_storage_type"] = "NSMutableDictionary"; + variables_["array_property_type"] = + "NSMutableDictionary<NSString*, " + + value_field_generator_->variable("storage_type") + "*>"; } else { - string base_name = MapEntryTypeName(key_descriptor, true); - base_name += MapEntryTypeName(value_descriptor, false); - base_name += "Dictionary"; - variables_["array_storage_type"] = "GPB" + base_name; + string class_name("GPB"); + class_name += MapEntryTypeName(key_descriptor, true); + class_name += MapEntryTypeName(value_descriptor, false); + class_name += "Dictionary"; + variables_["array_storage_type"] = class_name; + if (value_is_object_type) { + variables_["array_property_type"] = + class_name + "<" + + value_field_generator_->variable("storage_type") + "*>"; + } } } @@ -138,15 +150,9 @@ void MapFieldGenerator::FinishInitialization(void) { // values in the map are. const FieldDescriptor* value_descriptor = descriptor_->message_type()->FindFieldByName("value"); - ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); - if ((value_objc_type == OBJECTIVECTYPE_MESSAGE) || - (value_objc_type == OBJECTIVECTYPE_DATA) || - (value_objc_type == OBJECTIVECTYPE_STRING) || - (value_objc_type == OBJECTIVECTYPE_ENUM)) { + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) { variables_["array_comment"] = "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n"; - } else { - variables_["array_comment"] = ""; } } @@ -157,6 +163,19 @@ void MapFieldGenerator::GenerateFieldDescriptionTypeSpecific( value_field_generator_->GenerateFieldDescriptionTypeSpecific(printer); } +void MapFieldGenerator::DetermineForwardDeclarations( + set<string>* fwd_decls) const { + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); + const FieldDescriptor* value_descriptor = + descriptor_->message_type()->FindFieldByName("value"); + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) { + const string& value_storage_type = + value_field_generator_->variable("storage_type"); + fwd_decls->insert("@class " + value_storage_type); + } +} + + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h index 173541f2..7351ea05 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h @@ -41,18 +41,22 @@ namespace compiler { namespace objectivec { class MapFieldGenerator : public RepeatedFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); public: virtual void FinishInitialization(void); virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; protected: - explicit MapFieldGenerator(const FieldDescriptor* descriptor); + MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); virtual ~MapFieldGenerator(); + virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; + private: scoped_ptr<FieldGenerator> value_field_generator_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); }; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc index 32671d42..e0ea8bd2 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc @@ -174,10 +174,11 @@ const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) { } // namespace MessageGenerator::MessageGenerator(const string& root_classname, - const Descriptor* descriptor) + const Descriptor* descriptor, + const Options& options) : root_classname_(root_classname), descriptor_(descriptor), - field_generators_(descriptor), + field_generators_(descriptor, options), class_name_(ClassName(descriptor_)) { for (int i = 0; i < descriptor_->extension_count(); i++) { extension_generators_.push_back( @@ -196,7 +197,9 @@ MessageGenerator::MessageGenerator(const string& root_classname, for (int i = 0; i < descriptor_->nested_type_count(); i++) { MessageGenerator* generator = - new MessageGenerator(root_classname_, descriptor_->nested_type(i)); + new MessageGenerator(root_classname_, + descriptor_->nested_type(i), + options); nested_message_generators_.push_back(generator); } } @@ -230,11 +233,6 @@ void MessageGenerator::DetermineForwardDeclarations(set<string>* fwd_decls) { if (!IsMapEntryMessage(descriptor_)) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* fieldDescriptor = descriptor_->field(i); - // If it is a the field is repeated, the type will be and *Array, and we - // don't need any forward decl. - if (fieldDescriptor->is_repeated()) { - continue; - } field_generators_.get(fieldDescriptor) .DetermineForwardDeclarations(fwd_decls); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h index 06b536ff..8565e76f 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h @@ -54,7 +54,9 @@ class EnumGenerator; class MessageGenerator { public: - MessageGenerator(const string& root_classname, const Descriptor* descriptor); + MessageGenerator(const string& root_classname, + const Descriptor* descriptor, + const Options& options); ~MessageGenerator(); void GenerateStaticVariablesInitialization(io::Printer* printer); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc index f2ce4e5b..d6ccd6d1 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc @@ -58,8 +58,9 @@ void SetMessageVariables(const FieldDescriptor* descriptor, } // namespace -MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor) - : ObjCObjFieldGenerator(descriptor) { +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { SetMessageVariables(descriptor, &variables_); } @@ -67,6 +68,7 @@ MessageFieldGenerator::~MessageFieldGenerator() {} void MessageFieldGenerator::DetermineForwardDeclarations( set<string>* fwd_decls) const { + ObjCObjFieldGenerator::DetermineForwardDeclarations(fwd_decls); // Class name is already in "storage_type". fwd_decls->insert("@class " + variable("storage_type")); } @@ -82,14 +84,24 @@ bool MessageFieldGenerator::WantsHasProperty(void) const { } RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( - const FieldDescriptor* descriptor) - : RepeatedFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { SetMessageVariables(descriptor, &variables_); variables_["array_storage_type"] = "NSMutableArray"; + variables_["array_property_type"] = + "NSMutableArray<" + variables_["storage_type"] + "*>"; } RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} +void RepeatedMessageFieldGenerator::DetermineForwardDeclarations( + set<string>* fwd_decls) const { + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); + // Class name is already in "storage_type". + fwd_decls->insert("@class " + variable("storage_type")); +} + + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h index 708ea566..d2dba153 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h @@ -41,10 +41,12 @@ namespace compiler { namespace objectivec { class MessageFieldGenerator : public ObjCObjFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit MessageFieldGenerator(const FieldDescriptor* descriptor); + MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~MessageFieldGenerator(); virtual bool WantsHasProperty(void) const; @@ -56,12 +58,17 @@ class MessageFieldGenerator : public ObjCObjFieldGenerator { }; class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor); + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~RepeatedMessageFieldGenerator(); + public: + virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); }; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc index c185b66d..ea7f1b91 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc @@ -74,7 +74,7 @@ const char* PrimitiveTypeName(const FieldDescriptor* descriptor) { case OBJECTIVECTYPE_ENUM: return "int32_t"; case OBJECTIVECTYPE_MESSAGE: - return NULL; + return NULL; // Messages go through objectivec_message_field.cc|h. } // Some compilers report reaching end of function even though all cases of @@ -107,7 +107,8 @@ const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) { case OBJECTIVECTYPE_ENUM: return "Enum"; case OBJECTIVECTYPE_MESSAGE: - return ""; // Want NSArray + // Want NSArray (but goes through objectivec_message_field.cc|h). + return ""; } // Some compilers report reaching end of function even though all cases of @@ -126,16 +127,16 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, } // namespace PrimitiveFieldGenerator::PrimitiveFieldGenerator( - const FieldDescriptor* descriptor) - : SingleFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : SingleFieldGenerator(descriptor, options) { SetPrimitiveVariables(descriptor, &variables_); } PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator( - const FieldDescriptor* descriptor) - : ObjCObjFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { SetPrimitiveVariables(descriptor, &variables_); variables_["property_storage_attribute"] = "copy"; } @@ -143,8 +144,8 @@ PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator( PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {} RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( - const FieldDescriptor* descriptor) - : RepeatedFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { SetPrimitiveVariables(descriptor, &variables_); string base_name = PrimitiveArrayTypeName(descriptor); @@ -152,19 +153,13 @@ RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( variables_["array_storage_type"] = "GPB" + base_name + "Array"; } else { variables_["array_storage_type"] = "NSMutableArray"; + variables_["array_property_type"] = + "NSMutableArray<" + variables_["storage_type"] + "*>"; } } RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} -void RepeatedPrimitiveFieldGenerator::FinishInitialization(void) { - RepeatedFieldGenerator::FinishInitialization(); - if (IsPrimitiveType(descriptor_)) { - // No comment needed for primitive types. - variables_["array_comment"] = ""; - } -} - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h index 9bb79343..87139afb 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h @@ -41,10 +41,12 @@ namespace compiler { namespace objectivec { class PrimitiveFieldGenerator : public SingleFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor); + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~PrimitiveFieldGenerator(); private: @@ -52,10 +54,12 @@ class PrimitiveFieldGenerator : public SingleFieldGenerator { }; class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor); + PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~PrimitiveObjFieldGenerator(); private: @@ -63,12 +67,13 @@ class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator { }; class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor); + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~RepeatedPrimitiveFieldGenerator(); - virtual void FinishInitialization(void); private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); diff --git a/src/google/protobuf/stubs/atomicops.h b/src/google/protobuf/stubs/atomicops.h index cb93227f..9b3d1e6b 100644 --- a/src/google/protobuf/stubs/atomicops.h +++ b/src/google/protobuf/stubs/atomicops.h @@ -214,6 +214,8 @@ Atomic64 Release_Load(volatile const Atomic64* ptr); #include <google/protobuf/stubs/atomicops_internals_power.h> #elif defined(__native_client__) #include <google/protobuf/stubs/atomicops_internals_pnacl.h> +#elif defined(GOOGLE_PROTOBUF_ARCH_PPC) +#include <google/protobuf/stubs/atomicops_internals_ppc_gcc.h> #elif (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)) #include <google/protobuf/stubs/atomicops_internals_generic_gcc.h> #elif defined(__clang__) diff --git a/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h b/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h new file mode 100644 index 00000000..8231a578 --- /dev/null +++ b/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h @@ -0,0 +1,155 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +// Author: ogabbay@advaoptical.com (Oded Gabbay) +// Cleaned up by: bsilver16384@gmail.com (Brian Silverman) +// +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_ + +#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") + +namespace google { +namespace protobuf { +namespace internal { + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev; + + __asm__ __volatile__( + "0: \n\t" + "lwarx %[prev],0,%[ptr] \n\t" + "cmpw 0,%[prev],%[old_value] \n\t" + "bne- 1f \n\t" + "stwcx. %[new_value],0,%[ptr] \n\t" + "bne- 0b \n\t" + "1: \n\t" + : [prev] "=&r"(prev), "+m"(*ptr) + : [ptr] "r"(ptr), [old_value] "r"(old_value), [new_value] "r"(new_value) + : "cc", "memory"); + + return prev; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr, + Atomic32 new_value) { + Atomic32 old; + + __asm__ __volatile__( + "0: \n\t" + "lwarx %[old],0,%[ptr] \n\t" + "stwcx. %[new_value],0,%[ptr] \n\t" + "bne- 0b \n\t" + : [old] "=&r"(old), "+m"(*ptr) + : [ptr] "r"(ptr), [new_value] "r"(new_value) + : "cc", "memory"); + + return old; +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr, + Atomic32 increment) { + Atomic32 temp; + + __asm__ __volatile__( + "0: \n\t" + "lwarx %[temp],0,%[ptr] \n\t" + "add %[temp],%[increment],%[temp] \n\t" + "stwcx. %[temp],0,%[ptr] \n\t" + "bne- 0b \n\t" + : [temp] "=&r"(temp) + : [increment] "r"(increment), [ptr] "r"(ptr) + : "cc", "memory"); + + return temp; +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr, + Atomic32 increment) { + MemoryBarrier(); + Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment); + MemoryBarrier(); + return res; +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, Atomic32 new_value) { + Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + MemoryBarrier(); + return res; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, Atomic32 new_value) { + MemoryBarrier(); + Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + return res; +} + +inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) { + *ptr = value; +} + +inline void MemoryBarrier() { __asm__ __volatile__("sync" : : : "memory"); } + +inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) { return *ptr; } + +inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32 *ptr) { + MemoryBarrier(); + return *ptr; +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#undef ATOMICOPS_COMPILER_BARRIER + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_ diff --git a/src/google/protobuf/stubs/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h index 22b35723..4ba4b348 100644 --- a/src/google/protobuf/stubs/platform_macros.h +++ b/src/google/protobuf/stubs/platform_macros.h @@ -73,6 +73,9 @@ #elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__) #define GOOGLE_PROTOBUF_ARCH_POWER 1 #define GOOGLE_PROTOBUF_ARCH_64_BIT 1 +#elif defined(__PPC__) +#define GOOGLE_PROTOBUF_ARCH_PPC 1 +#define GOOGLE_PROTOBUF_ARCH_32_BIT 1 #elif defined(__GNUC__) # if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)) // We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h |