diff options
Diffstat (limited to 'src')
36 files changed, 1563 insertions, 413 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 1964a541..c8b85447 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -162,6 +162,7 @@ nobase_include_HEADERS = \ google/protobuf/compiler/js/js_generator.h \ google/protobuf/compiler/objectivec/objectivec_generator.h \ google/protobuf/compiler/objectivec/objectivec_helpers.h \ + google/protobuf/compiler/php/php_generator.h \ google/protobuf/compiler/python/python_generator.h \ google/protobuf/compiler/ruby/ruby_generator.h \ google/protobuf/util/type_resolver.h \ @@ -443,6 +444,7 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/objectivec/objectivec_oneof.h \ google/protobuf/compiler/objectivec/objectivec_primitive_field.cc \ google/protobuf/compiler/objectivec/objectivec_primitive_field.h \ + google/protobuf/compiler/php/php_generator.cc \ google/protobuf/compiler/python/python_generator.cc \ google/protobuf/compiler/ruby/ruby_generator.cc \ google/protobuf/compiler/csharp/csharp_doc_comment.cc \ diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc index 131ca206..d7fb644c 100644 --- a/src/google/protobuf/api.pb.cc +++ b/src/google/protobuf/api.pb.cc @@ -1006,7 +1006,7 @@ void Method::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 0ebf9b6a..dee438c6 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -719,6 +719,11 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } +TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) { + EXPECT_EQ("The system cannot find the file specified.\r\n", + Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND)); +} + #endif // defined(_WIN32) || defined(__CYGWIN__) TEST_F(CommandLineInterfaceTest, PathLookup) { diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index aa00962e..0034b121 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -2419,7 +2419,7 @@ GenerateClear(io::Printer* printer) { " &reinterpret_cast<$classname$*>(16)->f)\n" "#endif\n\n" "#define ZR_(first, last) do {\\\n" - " ::memset(&first, 0,\\\n" + " ::memset(&(first), 0,\\\n" " ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n" "} while (0)\n\n"; for (int i = 0; i < runs_of_fields_.size(); i++) { @@ -2956,7 +2956,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // on the CodedOutputStream. printer->Print( " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n" - " ::google::protobuf::internal::NewPermanentCallback(\n" + " ::google::protobuf::NewPermanentCallback(\n" " &MutableUnknownFieldsFor$classname$, this));\n" " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" " &unknown_fields_string, false);\n", diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 5d82946d..b7b6039a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -1252,7 +1252,7 @@ class GeneratedServiceTest : public testing::Test { foo_(descriptor_->FindMethodByName("Foo")), bar_(descriptor_->FindMethodByName("Bar")), stub_(&mock_channel_), - done_(::google::protobuf::internal::NewPermanentCallback(&DoNothing)) {} + done_(NewPermanentCallback(&DoNothing)) {} virtual void SetUp() { ASSERT_TRUE(foo_ != NULL); diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 2f3c5b8f..b83b8f32 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -35,8 +35,7 @@ #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/compiler/java/java_generator.h> #include <google/protobuf/compiler/javanano/javanano_generator.h> -// TODO(teboring): Add it back when php implementation is ready -// #include <google/protobuf/compiler/php/php_generator.h> +#include <google/protobuf/compiler/php/php_generator.h> #include <google/protobuf/compiler/ruby/ruby_generator.h> #include <google/protobuf/compiler/csharp/csharp_generator.h> #include <google/protobuf/compiler/objectivec/objectivec_generator.h> @@ -68,11 +67,10 @@ int main(int argc, char* argv[]) { cli.RegisterGenerator("--javanano_out", &javanano_generator, "Generate Java Nano source file."); - // TODO(teboring): Add it back when php implementation is ready // PHP - // google::protobuf::compiler::php::Generator php_generator; - // cli.RegisterGenerator("--php_out", &php_generator, - // "Generate PHP source file."); + google::protobuf::compiler::php::Generator php_generator; + cli.RegisterGenerator("--php_out", &php_generator, + "Generate PHP source file."); // Ruby google::protobuf::compiler::ruby::Generator rb_generator; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc index c0e7253a..d0de1eca 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc @@ -85,7 +85,7 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization( if (descriptor_->containing_type()->options().message_set_wire_format()) options.push_back("GPBExtensionSetWireFormat"); - vars["options"] = BuildFlagsString(options); + vars["options"] = BuildFlagsString(FLAGTYPE_EXTENSION, options); ObjectiveCType objc_type = GetObjectiveCType(descriptor_); string singular_type; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc index d2a6e882..527b7c0c 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -93,7 +93,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, field_flags.push_back("GPBFieldHasEnumDescriptor"); } - (*variables)["fieldflags"] = BuildFlagsString(field_flags); + (*variables)["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags); (*variables)["default"] = DefaultValue(descriptor); (*variables)["default_name"] = GPBGenericValueFieldName(descriptor); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index 438f4113..7ad127bb 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -37,6 +37,7 @@ #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> @@ -45,218 +46,120 @@ namespace google { namespace protobuf { - -// This is also found in GPBBootstrap.h, and needs to be kept in sync. It -// is the version check done to ensure generated code works with the current -// runtime being used. -const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001; - namespace compiler { namespace objectivec { namespace { -class ImportWriter { - public: - ImportWriter(const Options& options) - : options_(options), - need_to_parse_mapping_file_(true) {} - - void AddFile(const FileGenerator* file); - void Print(io::Printer *printer) const; - - private: - class ProtoFrameworkCollector : public LineConsumer { - public: - ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name) - : map_(inout_proto_file_to_framework_name) {} - - virtual bool ConsumeLine(const StringPiece& line, string* out_error); - - private: - map<string, string>* map_; - }; +// This is also found in GPBBootstrap.h, and needs to be kept in sync. +const int32 GOOGLE_PROTOBUF_OBJC_VERSION = 30002; - void ParseFrameworkMappings(); +const char* kHeaderExtension = ".pbobjc.h"; - const Options options_; - map<string, string> proto_file_to_framework_name_; - bool need_to_parse_mapping_file_; - - vector<string> protobuf_framework_imports_; - vector<string> protobuf_non_framework_imports_; - vector<string> other_framework_imports_; - vector<string> other_imports_; -}; - -void ImportWriter::AddFile(const FileGenerator* file) { - const FileDescriptor* file_descriptor = file->Descriptor(); - const string extension(".pbobjc.h"); - - if (IsProtobufLibraryBundledProtoFile(file_descriptor)) { - protobuf_framework_imports_.push_back( - FilePathBasename(file_descriptor) + extension); - protobuf_non_framework_imports_.push_back(file->Path() + extension); - return; +// 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; } - - // Lazy parse any mappings. - if (need_to_parse_mapping_file_) { - ParseFrameworkMappings(); + for (int i = 0; i < message->nested_type_count(); i++) { + if (MessageContainsExtensions(message->nested_type(i))) { + return true; + } } + return false; +} - map<string, string>::iterator proto_lookup = - proto_file_to_framework_name_.find(file_descriptor->name()); - if (proto_lookup != proto_file_to_framework_name_.end()) { - other_framework_imports_.push_back( - proto_lookup->second + "/" + - FilePathBasename(file_descriptor) + extension); - return; +// 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; } - - if (!options_.generate_for_named_framework.empty()) { - other_framework_imports_.push_back( - options_.generate_for_named_framework + "/" + - FilePathBasename(file_descriptor) + extension); - return; + for (int i = 0; i < file->message_type_count(); i++) { + if (MessageContainsExtensions(file->message_type(i))) { + return true; + } } - - other_imports_.push_back(file->Path() + extension); + return false; } -void ImportWriter::Print(io::Printer* printer) const { - assert(protobuf_non_framework_imports_.size() == - protobuf_framework_imports_.size()); - - bool add_blank_line = false; - - if (protobuf_framework_imports_.size() > 0) { - const string framework_name(ProtobufLibraryFrameworkName); - const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); - - printer->Print( - "#if $cpp_symbol$\n", - "cpp_symbol", cpp_symbol); - for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin(); - iter != protobuf_framework_imports_.end(); ++iter) { - printer->Print( - " #import <$framework_name$/$header$>\n", - "framework_name", framework_name, - "header", *iter); - } - printer->Print( - "#else\n"); - for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin(); - iter != protobuf_non_framework_imports_.end(); ++iter) { - printer->Print( - " #import \"$header$\"\n", - "header", *iter); - } - printer->Print( - "#endif\n"); - - add_blank_line = true; +// Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all +// deps as visited and prunes them from the needed files list. +void PruneFileAndDepsMarkingAsVisited( + const FileDescriptor* file, + vector<const FileDescriptor*>* files, + set<const FileDescriptor*>* files_visited) { + 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); + } +} - if (other_framework_imports_.size() > 0) { - if (add_blank_line) { - printer->Print("\n"); - } - - for (vector<string>::const_iterator iter = other_framework_imports_.begin(); - iter != other_framework_imports_.end(); ++iter) { - printer->Print( - " #import <$header$>\n", - "header", *iter); - } - - add_blank_line = true; +// Helper for CollectMinimalFileDepsContainingExtensions. +void CollectMinimalFileDepsContainingExtensionsWorker( + const FileDescriptor* file, + vector<const FileDescriptor*>* files, + set<const FileDescriptor*>* files_visited) { + if (files_visited->find(file) != files_visited->end()) { + return; } + files_visited->insert(file); - if (other_imports_.size() > 0) { - if (add_blank_line) { - printer->Print("\n"); + 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); } - - for (vector<string>::const_iterator iter = other_imports_.begin(); - iter != other_imports_.end(); ++iter) { - printer->Print( - " #import \"$header$\"\n", - "header", *iter); + } else { + for (int i = 0; i < file->dependency_count(); i++) { + const FileDescriptor* dep = file->dependency(i); + CollectMinimalFileDepsContainingExtensionsWorker(dep, files, + files_visited); } } } -void ImportWriter::ParseFrameworkMappings() { - need_to_parse_mapping_file_ = false; - if (options_.named_framework_to_proto_path_mappings_path.empty()) { - return; // Nothing to do. - } - - ProtoFrameworkCollector collector(&proto_file_to_framework_name_); - string parse_error; - if (!ParseSimpleFile(options_.named_framework_to_proto_path_mappings_path, - &collector, &parse_error)) { - cerr << "error parsing " << options_.named_framework_to_proto_path_mappings_path - << " : " << parse_error << endl; - cerr.flush(); +// 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, + vector<const FileDescriptor*>* files) { + 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 ImportWriter::ProtoFrameworkCollector::ConsumeLine( - const StringPiece& line, string* out_error) { - int offset = line.find(':'); - if (offset == StringPiece::npos) { - *out_error = - string("Framework/proto file mapping line without colon sign: '") + - line.ToString() + "'."; - return false; - } - StringPiece framework_name(line, 0, offset); - StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1); - StringPieceTrimWhitespace(&framework_name); - - int start = 0; - while (start < proto_file_list.length()) { - offset = proto_file_list.find(',', start); - if (offset == StringPiece::npos) { - offset = proto_file_list.length(); - } - - StringPiece proto_file(proto_file_list, start, offset - start); - StringPieceTrimWhitespace(&proto_file); - if (proto_file.size() != 0) { - map<string, string>::iterator existing_entry = - map_->find(proto_file.ToString()); - if (existing_entry != map_->end()) { - cerr << "warning: duplicate proto file reference, replacing framework entry for '" - << proto_file.ToString() << "' with '" << framework_name.ToString() - << "' (was '" << existing_entry->second << "')." << endl; - cerr.flush(); - } - - if (proto_file.find(' ') != StringPiece::npos) { - cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '" - << proto_file.ToString() << "'" << endl; - cerr.flush(); - } - - (*map_)[proto_file.ToString()] = framework_name.ToString(); +bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) { + for (int i = 0; i < file->dependency_count(); i++) { + if (dep == file->dependency(i)) { + return true; } - - start = offset + 1; } - - return true; + return false; } } // namespace - FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options) : file_(file), root_class_name_(FileClassName(file)), - is_public_dep_(false), options_(options) { for (int i = 0; i < file_->enum_type_count(); i++) { EnumGenerator *generator = new EnumGenerator(file_->enum_type(i)); @@ -275,8 +178,6 @@ FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options) } FileGenerator::~FileGenerator() { - STLDeleteContainerPointers(dependency_generators_.begin(), - dependency_generators_.end()); STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end()); STLDeleteContainerPointers(message_generators_.begin(), message_generators_.end()); @@ -289,24 +190,28 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { // 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_GEN_VERSION != $protoc_gen_objc_version$\n" - "#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.\n" + "#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", - "protoc_gen_objc_version", - SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION)); + "google_protobuf_objc_version", SimpleItoa(GOOGLE_PROTOBUF_OBJC_VERSION)); // #import any headers for "public imports" in the proto file. { - ImportWriter import_writer(options_); - const vector<FileGenerator *> &dependency_generators = DependencyGenerators(); - for (vector<FileGenerator *>::const_iterator iter = - dependency_generators.begin(); - iter != dependency_generators.end(); ++iter) { - if ((*iter)->IsPublicDependency()) { - import_writer.AddFile(*iter); - } + ImportWriter import_writer( + options_.generate_for_named_framework, + options_.named_framework_to_proto_path_mappings_path); + const string 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); } @@ -406,21 +311,41 @@ void FileGenerator::GenerateSource(io::Printer *printer) { // #import the runtime support. PrintFileRuntimePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h"); + vector<const FileDescriptor*> deps_with_extensions; + CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions); + { - ImportWriter import_writer(options_); + ImportWriter import_writer( + options_.generate_for_named_framework, + options_.named_framework_to_proto_path_mappings_path); + const string header_extension(kHeaderExtension); // #import the header for this proto file. - import_writer.AddFile(this); + 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). - const vector<FileGenerator *> &dependency_generators = - DependencyGenerators(); - for (vector<FileGenerator *>::const_iterator iter = - dependency_generators.begin(); - iter != dependency_generators.end(); ++iter) { - if (!(*iter)->IsPublicDependency()) { - import_writer.AddFile(*iter); + set<string> 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 (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); } } @@ -460,46 +385,37 @@ void FileGenerator::GenerateSource(io::Printer *printer) { "@implementation $root_class_name$\n\n", "root_class_name", root_class_name_); - // Generate the extension initialization structures for the top level and - // any nested messages. - ostringstream extensions_stringstream; - if (file_->extension_count() + file_->message_type_count() > 0) { - io::OstreamOutputStream extensions_outputstream(&extensions_stringstream); - io::Printer extensions_printer(&extensions_outputstream, '$'); - for (vector<ExtensionGenerator *>::iterator iter = - extension_generators_.begin(); - iter != extension_generators_.end(); ++iter) { - (*iter)->GenerateStaticVariablesInitialization(&extensions_printer); - } - for (vector<MessageGenerator *>::iterator iter = - message_generators_.begin(); - iter != message_generators_.end(); ++iter) { - (*iter)->GenerateStaticVariablesInitialization(&extensions_printer); - } - extensions_stringstream.flush(); - } + 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. - const string& extensions_str = extensions_stringstream.str(); - if (extensions_str.length() > 0 || file_->dependency_count() > 0) { + 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" - " GPBDebugCheckRuntimeVersion();\n" + " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n" " registry = [[GPBExtensionRegistry alloc] init];\n"); printer->Indent(); printer->Indent(); - if (extensions_str.length() > 0) { + if (file_contains_extensions) { printer->Print( "static GPBExtensionDescription descriptions[] = {\n"); printer->Indent(); - printer->Print(extensions_str.c_str()); + for (vector<ExtensionGenerator *>::iterator iter = + extension_generators_.begin(); + iter != extension_generators_.end(); ++iter) { + (*iter)->GenerateStaticVariablesInitialization(printer); + } + for (vector<MessageGenerator *>::iterator iter = + message_generators_.begin(); + iter != message_generators_.end(); ++iter) { + (*iter)->GenerateStaticVariablesInitialization(printer); + } printer->Outdent(); printer->Print( "};\n" @@ -512,14 +428,21 @@ void FileGenerator::GenerateSource(io::Printer *printer) { "}\n"); } - const vector<FileGenerator *> &dependency_generators = - DependencyGenerators(); - for (vector<FileGenerator *>::const_iterator iter = - dependency_generators.begin(); - iter != dependency_generators.end(); ++iter) { + 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( - "[registry addExtensions:[$dependency$ extensionRegistry]];\n", - "dependency", (*iter)->RootClassName()); + "// Merge in the imports (direct or indirect) that defined extensions.\n"); + for (vector<const FileDescriptor *>::iterator iter = + deps_with_extensions.begin(); + iter != deps_with_extensions.end(); ++iter) { + const string root_class_name(FileClassName((*iter))); + printer->Print( + "[registry addExtensions:[$dependency$ extensionRegistry]];\n", + "dependency", root_class_name); + } } printer->Outdent(); @@ -528,27 +451,39 @@ void FileGenerator::GenerateSource(io::Printer *printer) { printer->Print( " }\n" " return registry;\n" - "}\n" - "\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("@end\n\n"); + printer->Print("\n@end\n\n"); // File descriptor only needed if there are messages to use it. if (message_generators_.size() > 0) { - string syntax; + map<string, string> vars; + vars["root_class_name"] = root_class_name_; + vars["package"] = file_->package(); + vars["objc_prefix"] = FileClassPrefix(file_); switch (file_->syntax()) { case FileDescriptor::SYNTAX_UNKNOWN: - syntax = "GPBFileSyntaxUnknown"; + vars["syntax"] = "GPBFileSyntaxUnknown"; break; case FileDescriptor::SYNTAX_PROTO2: - syntax = "GPBFileSyntaxProto2"; + vars["syntax"] = "GPBFileSyntaxProto2"; break; case FileDescriptor::SYNTAX_PROTO3: - syntax = "GPBFileSyntaxProto3"; + vars["syntax"] = "GPBFileSyntaxProto3"; break; } - printer->Print( + printer->Print(vars, "#pragma mark - $root_class_name$_FileDescriptor\n" "\n" "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n" @@ -556,16 +491,24 @@ void FileGenerator::GenerateSource(io::Printer *printer) { " // about thread safety of the singleton.\n" " static GPBFileDescriptor *descriptor = NULL;\n" " if (!descriptor) {\n" - " GPBDebugCheckRuntimeVersion();\n" - " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" - " syntax:$syntax$];\n" + " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"); + if (vars["objc_prefix"].size() > 0) { + 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", - "root_class_name", root_class_name_, - "package", file_->package(), - "syntax", syntax); + "\n"); } for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin(); @@ -584,24 +527,6 @@ void FileGenerator::GenerateSource(io::Printer *printer) { "// @@protoc_insertion_point(global_scope)\n"); } -const vector<FileGenerator *> &FileGenerator::DependencyGenerators() { - if (file_->dependency_count() != dependency_generators_.size()) { - set<string> 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++) { - 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); - dependency_generators_.push_back(generator); - } - } - return dependency_generators_; -} - // 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. diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h index 8e4388d8..a60a6885 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h @@ -62,32 +62,17 @@ class FileGenerator { void GenerateHeader(io::Printer* printer); const string& RootClassName() const { return root_class_name_; } - const string Path() const { return FilePath(file_); } - const FileDescriptor* Descriptor() const { return file_; } - - bool IsPublicDependency() const { return is_public_dep_; } - - protected: - void SetIsPublicDependency(bool is_public_dep) { - is_public_dep_ = is_public_dep; - } private: const FileDescriptor* file_; string root_class_name_; - // Access this field through the DependencyGenerators accessor call below. - // Do not reference it directly. - vector<FileGenerator*> dependency_generators_; - vector<EnumGenerator*> enum_generators_; vector<MessageGenerator*> message_generators_; vector<ExtensionGenerator*> extension_generators_; - bool is_public_dep_; const Options options_; - const vector<FileGenerator*>& DependencyGenerators(); void PrintFileRuntimePreamble( io::Printer* printer, const string& header_to_import) const; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc index a0b6d6cb..36407467 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc @@ -45,10 +45,22 @@ ObjectiveCGenerator::ObjectiveCGenerator() {} ObjectiveCGenerator::~ObjectiveCGenerator() {} +bool ObjectiveCGenerator::HasGenerateAll() const { + return true; +} + bool ObjectiveCGenerator::Generate(const FileDescriptor* file, const string& parameter, - OutputDirectory* output_directory, + GeneratorContext* context, string* error) const { + *error = "Unimplemented Generate() method. Call GenerateAll() instead."; + return false; +} + +bool ObjectiveCGenerator::GenerateAll(const vector<const FileDescriptor*>& files, + const string& parameter, + GeneratorContext* context, + string* error) const { // ----------------------------------------------------------------- // Parse generator options. These options are passed to the compiler using the // --objc_opt flag. The options are passed as a comma separated list of @@ -117,29 +129,32 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file, // ----------------------------------------------------------------- - // Validate the objc prefix/package pairing. - if (!ValidateObjCClassPrefix(file, generation_options, error)) { + // Validate the objc prefix/package pairings. + if (!ValidateObjCClassPrefixes(files, generation_options, error)) { // *error will have been filled in. return false; } - FileGenerator file_generator(file, generation_options); - string filepath = FilePath(file); + for (int i = 0; i < files.size(); i++) { + const FileDescriptor* file = files[i]; + FileGenerator file_generator(file, generation_options); + string filepath = FilePath(file); - // Generate header. - { - scoped_ptr<io::ZeroCopyOutputStream> output( - output_directory->Open(filepath + ".pbobjc.h")); - io::Printer printer(output.get(), '$'); - file_generator.GenerateHeader(&printer); - } + // Generate header. + { + scoped_ptr<io::ZeroCopyOutputStream> output( + context->Open(filepath + ".pbobjc.h")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateHeader(&printer); + } - // Generate m file. - { - scoped_ptr<io::ZeroCopyOutputStream> output( - output_directory->Open(filepath + ".pbobjc.m")); - io::Printer printer(output.get(), '$'); - file_generator.GenerateSource(&printer); + // Generate m file. + { + scoped_ptr<io::ZeroCopyOutputStream> output( + context->Open(filepath + ".pbobjc.m")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSource(&printer); + } } return true; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.h b/src/google/protobuf/compiler/objectivec/objectivec_generator.h index 9ddca574..b1723318 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.h @@ -51,8 +51,15 @@ class LIBPROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator { ~ObjectiveCGenerator(); // implements CodeGenerator ---------------------------------------- - bool Generate(const FileDescriptor* file, const string& parameter, - OutputDirectory* output_directory, string* error) const; + bool HasGenerateAll() const; + bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* context, + string* error) const; + bool GenerateAll(const vector<const FileDescriptor*>& files, + const string& parameter, + GeneratorContext* context, + string* error) const; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectiveCGenerator); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index 4a94373a..c7fd96ac 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -44,9 +44,10 @@ #include <google/protobuf/stubs/hash.h> #include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> @@ -209,10 +210,14 @@ const char* const kReservedWordList[] = { hash_set<string> kReservedWords = MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList)); -string SanitizeNameForObjC(const string& input, const string& extension) { +string SanitizeNameForObjC(const string& input, + const string& extension, + string* out_suffix_added) { if (kReservedWords.count(input) > 0) { + if (out_suffix_added) *out_suffix_added = extension; return input + extension; } + if (out_suffix_added) out_suffix_added->clear(); return input; } @@ -261,6 +266,34 @@ bool IsSpecialName(const string& name, const string* special_names, return false; } +string GetZeroEnumNameForFlagType(const FlagType flag_type) { + switch(flag_type) { + case FLAGTYPE_DESCRIPTOR_INITIALIZATION: + return "GPBDescriptorInitializationFlag_None"; + case FLAGTYPE_EXTENSION: + return "GPBExtensionNone"; + case FLAGTYPE_FIELD: + return "GPBFieldNone"; + default: + GOOGLE_LOG(FATAL) << "Can't get here."; + return "0"; + } +} + +string GetEnumNameForFlagType(const FlagType flag_type) { + switch(flag_type) { + case FLAGTYPE_DESCRIPTOR_INITIALIZATION: + return "GPBDescriptorInitializationFlags"; + case FLAGTYPE_EXTENSION: + return "GPBExtensionOptions"; + case FLAGTYPE_FIELD: + return "GPBFieldFlags"; + default: + GOOGLE_LOG(FATAL) << "Can't get here."; + return string(); + } +} + } // namespace // Escape C++ trigraphs by escaping question marks to \? @@ -307,6 +340,12 @@ string BaseFileName(const FileDescriptor* file) { return basename; } +string FileClassPrefix(const FileDescriptor* file) { + // Default is empty string, no need to check has_objc_class_prefix. + string result = file->options().objc_class_prefix(); + return result; +} + string FilePath(const FileDescriptor* file) { string output; string basename; @@ -337,19 +376,13 @@ string FilePathBasename(const FileDescriptor* file) { return output; } -string FileClassPrefix(const FileDescriptor* file) { - // Default is empty string, no need to check has_objc_class_prefix. - string result = file->options().objc_class_prefix(); - return result; -} - string FileClassName(const FileDescriptor* file) { string name = FileClassPrefix(file); name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true); name += "Root"; // There aren't really any reserved words that end in "Root", but playing // it safe and checking. - return SanitizeNameForObjC(name, "_RootClass"); + return SanitizeNameForObjC(name, "_RootClass", NULL); } string ClassNameWorker(const Descriptor* descriptor) { @@ -371,11 +404,15 @@ string ClassNameWorker(const EnumDescriptor* descriptor) { } string ClassName(const Descriptor* descriptor) { + return ClassName(descriptor, NULL); +} + +string ClassName(const Descriptor* descriptor, string* out_suffix_added) { // 1. Message names are used as is (style calls for CamelCase, trust it). // 2. Check for reserved word at the very end and then suffix things. string prefix = FileClassPrefix(descriptor->file()); string name = ClassNameWorker(descriptor); - return SanitizeNameForObjC(prefix + name, "_Class"); + return SanitizeNameForObjC(prefix + name, "_Class", out_suffix_added); } string EnumName(const EnumDescriptor* descriptor) { @@ -389,7 +426,7 @@ string EnumName(const EnumDescriptor* descriptor) { // yields Fixed_Class, Fixed_Size. string name = FileClassPrefix(descriptor->file()); name += ClassNameWorker(descriptor); - return SanitizeNameForObjC(name, "_Enum"); + return SanitizeNameForObjC(name, "_Enum", NULL); } string EnumValueName(const EnumValueDescriptor* descriptor) { @@ -404,7 +441,7 @@ string EnumValueName(const EnumValueDescriptor* descriptor) { const string& name = class_name + "_" + value_str; // There aren't really any reserved words with an underscore and a leading // capital letter, but playing it safe and checking. - return SanitizeNameForObjC(name, "_Value"); + return SanitizeNameForObjC(name, "_Value", NULL); } string EnumValueShortName(const EnumValueDescriptor* descriptor) { @@ -441,7 +478,7 @@ string UnCamelCaseEnumShortName(const string& name) { string ExtensionMethodName(const FieldDescriptor* descriptor) { const string& name = NameFromFieldDescriptor(descriptor); const string& result = UnderscoresToCamelCase(name, false); - return SanitizeNameForObjC(result, "_Extension"); + return SanitizeNameForObjC(result, "_Extension", NULL); } string FieldName(const FieldDescriptor* field) { @@ -456,7 +493,7 @@ string FieldName(const FieldDescriptor* field) { result += "_p"; } } - return SanitizeNameForObjC(result, "_p"); + return SanitizeNameForObjC(result, "_p", NULL); } string FieldNameCapitalized(const FieldDescriptor* field) { @@ -816,17 +853,21 @@ bool HasNonZeroDefaultValue(const FieldDescriptor* field) { return false; } -string BuildFlagsString(const vector<string>& strings) { +string BuildFlagsString(const FlagType flag_type, + const vector<string>& strings) { if (strings.size() == 0) { - return "0"; + return GetZeroEnumNameForFlagType(flag_type); + } else if (strings.size() == 1) { + return strings[0]; } - string string; + string string("(" + GetEnumNameForFlagType(flag_type) + ")("); for (size_t i = 0; i != strings.size(); ++i) { if (i > 0) { string.append(" | "); } string.append(strings[i]); } + string.append(")"); return string; } @@ -979,28 +1020,20 @@ bool LoadExpectedPackagePrefixes(const Options &generation_options, generation_options.expected_prefixes_path, &collector, out_error); } -} // namespace - -bool ValidateObjCClassPrefix(const FileDescriptor* file, - const Options& generation_options, - string* out_error) { +bool ValidateObjCClassPrefix( + const FileDescriptor* file, + const string& expected_prefixes_path, + const map<string, string>& expected_package_prefixes, + string* out_error) { const string prefix = file->options().objc_class_prefix(); const string package = file->package(); // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some // error cases, so it seems to be ok to use as a back door for warnings. - // Load any expected package prefixes to validate against those. - map<string, string> expected_package_prefixes; - if (!LoadExpectedPackagePrefixes(generation_options, - &expected_package_prefixes, - out_error)) { - return false; - } - // Check: Error - See if there was an expected prefix for the package and // report if it doesn't match (wrong or missing). - map<string, string>::iterator package_match = + map<string, string>::const_iterator package_match = expected_package_prefixes.find(package); if (package_match != expected_package_prefixes.end()) { // There was an entry, and... @@ -1021,27 +1054,11 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, } // If there was no prefix option, we're done at this point. - if (prefix.length() == 0) { + if (prefix.empty()) { // No prefix, nothing left to check. return true; } - // Check: Error - Make sure the prefix wasn't expected for a different - // package (overlap is allowed, but it has to be listed as an expected - // overlap). - for (map<string, string>::iterator i = expected_package_prefixes.begin(); - i != expected_package_prefixes.end(); ++i) { - if (i->second == prefix) { - *out_error = - "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 (" + - generation_options.expected_prefixes_path + ")."; - return false; // Only report first usage of the prefix. - } - } - // Check: Warning - Make sure the prefix is is a reasonable value according // to Apple's rules (the checks above implicitly whitelist anything that // doesn't meet these rules). @@ -1063,6 +1080,56 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, cerr.flush(); } + // Look for any other package that uses the same prefix. + string other_package_for_prefix; + for (map<string, string>::const_iterator i = expected_package_prefixes.begin(); + i != expected_package_prefixes.end(); ++i) { + if (i->second == prefix) { + other_package_for_prefix = i->first; + break; + } + } + + // Check: Warning - If the file does not have a package, check whether + // the prefix declared is being used by another package or not. + if (package.empty()) { + // The file does not have a package and ... + if (other_package_for_prefix.empty()) { + // ... no other package has declared that prefix. + cerr << endl + << "protoc:0: warning: File '" << file->name() << "' has no " + << "package. Consider adding a new package to the proto and adding '" + << "new.package = " << prefix << "' to the expected prefixes file (" + << expected_prefixes_path << ")." << endl; + cerr.flush(); + } else { + // ... another package has declared the same prefix. + cerr << endl + << "protoc:0: warning: File '" << file->name() << "' has no package " + << "and package '" << other_package_for_prefix << "' already uses '" + << prefix << "' as its prefix. Consider either adding a new package " + << "to the proto, or reusing one of the packages already using this " + << "prefix in the expected prefixes file (" + << expected_prefixes_path << ")." << endl; + cerr.flush(); + } + return true; + } + + // Check: Error - Make sure the prefix wasn't expected for a different + // package (overlap is allowed, but it has to be listed as an expected + // overlap). + if (!other_package_for_prefix.empty()) { + *out_error = + "error: Found 'option objc_class_prefix = \"" + prefix + + "\";' in '" + file->name() + + "'; that prefix is already used for 'package " + + other_package_for_prefix + ";'. It can only be reused by listing " + + "it in the expected file (" + + expected_prefixes_path + ")."; + return false; // Only report first usage of the prefix. + } + // Check: Warning - If the given package/prefix pair wasn't expected, issue a // warning issue a warning suggesting it gets added to the file. if (!expected_package_prefixes.empty()) { @@ -1070,13 +1137,39 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" << prefix << "\";' in '" << file->name() << "';" << " consider adding it to the expected prefixes file (" - << generation_options.expected_prefixes_path << ")." << endl; + << expected_prefixes_path << ")." << endl; cerr.flush(); } return true; } +} // namespace + +bool ValidateObjCClassPrefixes(const vector<const FileDescriptor*>& files, + const Options& generation_options, + string* out_error) { + // Load the expected package prefixes, if available, to validate against. + map<string, string> expected_package_prefixes; + if (!LoadExpectedPackagePrefixes(generation_options, + &expected_package_prefixes, + out_error)) { + return false; + } + + for (int i = 0; i < files.size(); i++) { + bool is_valid = + ValidateObjCClassPrefix(files[i], + generation_options.expected_prefixes_path, + expected_package_prefixes, + out_error); + if (!is_valid) { + return false; + } + } + return true; +} + TextFormatDecodeData::TextFormatDecodeData() { } TextFormatDecodeData::~TextFormatDecodeData() { } @@ -1399,6 +1492,178 @@ bool ParseSimpleFile( return parser.Finish(); } +ImportWriter::ImportWriter( + const string& generate_for_named_framework, + const string& named_framework_to_proto_path_mappings_path) + : generate_for_named_framework_(generate_for_named_framework), + named_framework_to_proto_path_mappings_path_( + named_framework_to_proto_path_mappings_path), + need_to_parse_mapping_file_(true) { +} + +ImportWriter::~ImportWriter() {} + +void ImportWriter::AddFile(const FileDescriptor* file, + const string& header_extension) { + const string file_path(FilePath(file)); + + if (IsProtobufLibraryBundledProtoFile(file)) { + protobuf_framework_imports_.push_back( + FilePathBasename(file) + header_extension); + protobuf_non_framework_imports_.push_back(file_path + header_extension); + return; + } + + // Lazy parse any mappings. + if (need_to_parse_mapping_file_) { + ParseFrameworkMappings(); + } + + map<string, string>::iterator proto_lookup = + proto_file_to_framework_name_.find(file->name()); + if (proto_lookup != proto_file_to_framework_name_.end()) { + other_framework_imports_.push_back( + proto_lookup->second + "/" + + FilePathBasename(file) + header_extension); + return; + } + + if (!generate_for_named_framework_.empty()) { + other_framework_imports_.push_back( + generate_for_named_framework_ + "/" + + FilePathBasename(file) + header_extension); + return; + } + + other_imports_.push_back(file_path + header_extension); +} + +void ImportWriter::Print(io::Printer* printer) const { + assert(protobuf_non_framework_imports_.size() == + protobuf_framework_imports_.size()); + + bool add_blank_line = false; + + if (protobuf_framework_imports_.size() > 0) { + const string framework_name(ProtobufLibraryFrameworkName); + const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); + + printer->Print( + "#if $cpp_symbol$\n", + "cpp_symbol", cpp_symbol); + for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin(); + iter != protobuf_framework_imports_.end(); ++iter) { + printer->Print( + " #import <$framework_name$/$header$>\n", + "framework_name", framework_name, + "header", *iter); + } + printer->Print( + "#else\n"); + for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin(); + iter != protobuf_non_framework_imports_.end(); ++iter) { + printer->Print( + " #import \"$header$\"\n", + "header", *iter); + } + printer->Print( + "#endif\n"); + + add_blank_line = true; + } + + if (other_framework_imports_.size() > 0) { + if (add_blank_line) { + printer->Print("\n"); + } + + for (vector<string>::const_iterator iter = other_framework_imports_.begin(); + iter != other_framework_imports_.end(); ++iter) { + printer->Print( + " #import <$header$>\n", + "header", *iter); + } + + add_blank_line = true; + } + + if (other_imports_.size() > 0) { + if (add_blank_line) { + printer->Print("\n"); + } + + for (vector<string>::const_iterator iter = other_imports_.begin(); + iter != other_imports_.end(); ++iter) { + printer->Print( + " #import \"$header$\"\n", + "header", *iter); + } + } +} + +void ImportWriter::ParseFrameworkMappings() { + need_to_parse_mapping_file_ = false; + if (named_framework_to_proto_path_mappings_path_.empty()) { + return; // Nothing to do. + } + + ProtoFrameworkCollector collector(&proto_file_to_framework_name_); + string parse_error; + if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_, + &collector, &parse_error)) { + cerr << "error parsing " << named_framework_to_proto_path_mappings_path_ + << " : " << parse_error << endl; + cerr.flush(); + } +} + +bool ImportWriter::ProtoFrameworkCollector::ConsumeLine( + const StringPiece& line, string* out_error) { + int offset = line.find(':'); + if (offset == StringPiece::npos) { + *out_error = + string("Framework/proto file mapping line without colon sign: '") + + line.ToString() + "'."; + return false; + } + StringPiece framework_name(line, 0, offset); + StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1); + StringPieceTrimWhitespace(&framework_name); + + int start = 0; + while (start < proto_file_list.length()) { + offset = proto_file_list.find(',', start); + if (offset == StringPiece::npos) { + offset = proto_file_list.length(); + } + + StringPiece proto_file(proto_file_list, start, offset - start); + StringPieceTrimWhitespace(&proto_file); + if (proto_file.size() != 0) { + map<string, string>::iterator existing_entry = + map_->find(proto_file.ToString()); + if (existing_entry != map_->end()) { + cerr << "warning: duplicate proto file reference, replacing framework entry for '" + << proto_file.ToString() << "' with '" << framework_name.ToString() + << "' (was '" << existing_entry->second << "')." << endl; + cerr.flush(); + } + + if (proto_file.find(' ') != StringPiece::npos) { + cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '" + << proto_file.ToString() << "'" << endl; + cerr.flush(); + } + + (*map_)[proto_file.ToString()] = framework_name.ToString(); + } + + start = offset + 1; + } + + return true; +} + } // namespace objectivec } // namespace compiler diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index c96d5ea5..316069e1 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -69,6 +69,9 @@ bool IsRetainedName(const string& name); // handling under ARC. bool IsInitName(const string& name); +// Gets the objc_class_prefix. +string FileClassPrefix(const FileDescriptor* file); + // Gets the path of the file we're going to generate (sans the .pb.h // extension). The path will be dependent on the objectivec package // declared in the proto package. @@ -85,6 +88,7 @@ string FileClassName(const FileDescriptor* file); // These return the fully-qualified class name corresponding to the given // descriptor. string ClassName(const Descriptor* descriptor); +string ClassName(const Descriptor* descriptor, string* out_suffix_added); string EnumName(const EnumDescriptor* descriptor); // Returns the fully-qualified name of the enum value corresponding to the @@ -139,6 +143,12 @@ enum ObjectiveCType { OBJECTIVECTYPE_MESSAGE }; +enum FlagType { + FLAGTYPE_DESCRIPTOR_INITIALIZATION, + FLAGTYPE_EXTENSION, + FLAGTYPE_FIELD +}; + template<class TDescriptor> string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, bool preSpace = true, bool postNewline = false) { if (descriptor->options().deprecated()) { @@ -170,7 +180,7 @@ string GPBGenericValueFieldName(const FieldDescriptor* field); string DefaultValue(const FieldDescriptor* field); bool HasNonZeroDefaultValue(const FieldDescriptor* field); -string BuildFlagsString(const vector<string>& strings); +string BuildFlagsString(const FlagType type, const vector<string>& strings); // Builds HeaderDoc/appledoc style comments out of the comments in the .proto // file. @@ -187,12 +197,12 @@ string ProtobufFrameworkImportSymbol(const string& framework_name); // Checks if the file is one of the proto's bundled with the library. bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file); -// 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, - const Options& generation_options, - string* out_error); +// Checks the prefix for the given files and outputs any warnings as needed. If +// there are flat out errors, then out_error is filled in with the first error +// and the result is false. +bool ValidateObjCClassPrefixes(const vector<const FileDescriptor*>& files, + const Options& generation_options, + string* out_error); // Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform // the input into the expected output. @@ -227,6 +237,43 @@ class LIBPROTOC_EXPORT LineConsumer { bool ParseSimpleFile( const string& path, LineConsumer* line_consumer, string* out_error); + +// Helper class for parsing framework import mappings and generating +// import statements. +class LIBPROTOC_EXPORT ImportWriter { + public: + ImportWriter(const string& generate_for_named_framework, + const string& named_framework_to_proto_path_mappings_path); + ~ImportWriter(); + + void AddFile(const FileDescriptor* file, const string& header_extension); + void Print(io::Printer *printer) const; + + private: + class ProtoFrameworkCollector : public LineConsumer { + public: + ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name) + : map_(inout_proto_file_to_framework_name) {} + + virtual bool ConsumeLine(const StringPiece& line, string* out_error); + + private: + map<string, string>* map_; + }; + + void ParseFrameworkMappings(); + + const string generate_for_named_framework_; + const string named_framework_to_proto_path_mappings_path_; + map<string, string> proto_file_to_framework_name_; + bool need_to_parse_mapping_file_; + + vector<string> protobuf_framework_imports_; + vector<string> protobuf_non_framework_imports_; + vector<string> other_framework_imports_; + vector<string> other_imports_; +}; + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc index ac5d8aea..0bc9dc10 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -115,7 +115,7 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, if (value_field_flags.find("GPBFieldHasEnumDescriptor") != string::npos) { field_flags.push_back("GPBFieldHasEnumDescriptor"); } - variables_["fieldflags"] = BuildFlagsString(field_flags); + variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags); ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); const bool value_is_object_type = diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc index 822da893..4c6e1b55 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc @@ -521,7 +521,8 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { if (descriptor_->options().message_set_wire_format()) { init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat"); } - vars["init_flags"] = BuildFlagsString(init_flags); + vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION, + init_flags); printer->Print( vars, @@ -579,6 +580,19 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " [localDescriptor setupExtensionRanges:ranges\n" " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); } + if (descriptor_->containing_type() != NULL) { + string parent_class_name = ClassName(descriptor_->containing_type()); + printer->Print( + " [localDescriptor setupContainingMessageClassName:GPBStringifySymbol($parent_name$)];\n", + "parent_name", parent_class_name); + } + string suffix_added; + ClassName(descriptor_, &suffix_added); + if (suffix_added.size() > 0) { + printer->Print( + " [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n", + "suffix", suffix_added); + } printer->Print( " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" " descriptor = localDescriptor;\n" diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 214d7c9c..09c7a2b6 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -525,7 +525,6 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { SourceCodeInfo source_code_info; source_code_info_ = &source_code_info; - vector<string> top_doc_comments; if (LookingAtType(io::Tokenizer::TYPE_START)) { // Advance to first token. input_->NextWithComments(NULL, &upcoming_detached_comments_, @@ -571,6 +570,7 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { input_ = NULL; source_code_info_ = NULL; + assert(file != NULL); source_code_info.Swap(file->mutable_source_code_info()); return !had_errors_; } diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc new file mode 100644 index 00000000..75ddb405 --- /dev/null +++ b/src/google/protobuf/compiler/php/php_generator.cc @@ -0,0 +1,781 @@ +// 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/php/php_generator.h> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/strutil.h> + +#include <sstream> + +using google::protobuf::internal::scoped_ptr; + +const std::string kDescriptorFile = "google/protobuf/descriptor.proto"; +const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal"; + +namespace google { +namespace protobuf { +namespace compiler { +namespace php { + +// Forward decls. +std::string PhpName(const std::string& full_name, bool is_descriptor); +std::string DefaultForField(google::protobuf::FieldDescriptor* field); +std::string IntToString(int32 value); +std::string GeneratedFileName(const std::string& proto_file, + bool is_descriptor); +std::string LabelForField(google::protobuf::FieldDescriptor* field); +std::string TypeName(google::protobuf::FieldDescriptor* field); +std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter); +std::string EscapeDollor(const string& to_escape); +std::string BinaryToHex(const string& binary); +void GenerateMessage(const string& name_prefix, + const google::protobuf::Descriptor* message, + bool is_descriptor, + google::protobuf::io::Printer* printer); +void GenerateEnum(const google::protobuf::EnumDescriptor* en, + google::protobuf::io::Printer* printer); +void Indent(google::protobuf::io::Printer* printer); +void Outdent(google::protobuf::io::Printer* printer); + +std::string MessageName(const google::protobuf::Descriptor* message, + bool is_descriptor) { + string message_name = message->name(); + const google::protobuf::Descriptor* descriptor = message->containing_type(); + while (descriptor != NULL) { + message_name = descriptor->name() + '_' + message_name; + descriptor = descriptor->containing_type(); + } + return PhpName(message->file()->package(), is_descriptor) + '\\' + + message_name; +} + +std::string MessageFullName(const google::protobuf::Descriptor* message, + bool is_descriptor) { + if (is_descriptor) { + return StringReplace(message->full_name(), + "google.protobuf", + "google.protobuf.internal", false); + } else { + return message->full_name(); + } +} + +std::string EnumFullName(const google::protobuf::EnumDescriptor* envm, + bool is_descriptor) { + if (is_descriptor) { + return StringReplace(envm->full_name(), + "google.protobuf", + "google.protobuf.internal", false); + } else { + return envm->full_name(); + } +} + +std::string EnumClassName(const google::protobuf::EnumDescriptor* envm) { + string enum_class_name = envm->name(); + const google::protobuf::Descriptor* descriptor = envm->containing_type(); + while (descriptor != NULL) { + enum_class_name = descriptor->name() + '_' + enum_class_name; + descriptor = descriptor->containing_type(); + } + return enum_class_name; +} + +std::string EnumName(const google::protobuf::EnumDescriptor* envm, + bool is_descriptor) { + string enum_name = EnumClassName(envm); + return PhpName(envm->file()->package(), is_descriptor) + '\\' + enum_name; +} + +std::string PhpName(const std::string& full_name, bool is_descriptor) { + if (is_descriptor) { + return kDescriptorPackageName; + } + + std::string result; + bool cap_next_letter = true; + for (int i = 0; i < full_name.size(); i++) { + if ('a' <= full_name[i] && full_name[i] <= 'z' && cap_next_letter) { + result += full_name[i] + ('A' - 'a'); + cap_next_letter = false; + } else if (full_name[i] == '.') { + result += '\\'; + cap_next_letter = true; + } else { + result += full_name[i]; + cap_next_letter = false; + } + } + return result; +} + +std::string DefaultForField(const google::protobuf::FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_ENUM: return "0"; + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: return "0.0"; + case FieldDescriptor::TYPE_BOOL: return "false"; + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: return "''"; + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: return "null"; + default: assert(false); return ""; + } +} + +std::string GeneratedFileName(const std::string& proto_file, + bool is_descriptor) { + if (is_descriptor) { + return "descriptor_internal.pb.php"; + } else { + int lastindex = proto_file.find_last_of("."); + return proto_file.substr(0, lastindex) + ".pb.php"; + } +} + +std::string IntToString(int32 value) { + std::ostringstream os; + os << value; + return os.str(); +} + +std::string LabelForField(const google::protobuf::FieldDescriptor* field) { + switch (field->label()) { + case FieldDescriptor::LABEL_OPTIONAL: return "optional"; + case FieldDescriptor::LABEL_REQUIRED: return "required"; + case FieldDescriptor::LABEL_REPEATED: return "repeated"; + default: assert(false); return ""; + } +} + +std::string TypeName(const google::protobuf::FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: return "int32"; + case FieldDescriptor::TYPE_INT64: return "int64"; + case FieldDescriptor::TYPE_UINT32: return "uint32"; + case FieldDescriptor::TYPE_UINT64: return "uint64"; + case FieldDescriptor::TYPE_SINT32: return "sint32"; + case FieldDescriptor::TYPE_SINT64: return "sint64"; + case FieldDescriptor::TYPE_FIXED32: return "fixed32"; + case FieldDescriptor::TYPE_FIXED64: return "fixed64"; + case FieldDescriptor::TYPE_SFIXED32: return "sfixed32"; + case FieldDescriptor::TYPE_SFIXED64: return "sfixed64"; + case FieldDescriptor::TYPE_DOUBLE: return "double"; + case FieldDescriptor::TYPE_FLOAT: return "float"; + case FieldDescriptor::TYPE_BOOL: return "bool"; + case FieldDescriptor::TYPE_ENUM: return "enum"; + case FieldDescriptor::TYPE_STRING: return "string"; + case FieldDescriptor::TYPE_BYTES: return "bytes"; + case FieldDescriptor::TYPE_MESSAGE: return "message"; + case FieldDescriptor::TYPE_GROUP: return "group"; + default: assert(false); return ""; + } +} + +std::string EnumOrMessageSuffix( + const google::protobuf::FieldDescriptor* field, bool is_descriptor) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + return ", '" + MessageFullName(field->message_type(), is_descriptor) + "'"; + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + return ", '" + EnumFullName(field->enum_type(), is_descriptor) + "'"; + } + return ""; +} + +// Converts a name to camel-case. If cap_first_letter is true, capitalize the +// first letter. +std::string UnderscoresToCamelCase(const string& input, bool cap_first_letter) { + std::string result; + for (int i = 0; i < input.size(); i++) { + if ('a' <= input[i] && input[i] <= 'z') { + if (cap_first_letter) { + result += input[i] + ('A' - 'a'); + } else { + result += input[i]; + } + cap_first_letter = false; + } else if ('A' <= input[i] && input[i] <= 'Z') { + if (i == 0 && !cap_first_letter) { + // Force first letter to lower-case unless explicitly told to + // capitalize it. + result += input[i] + ('a' - 'A'); + } else { + // Capital letters after the first are left as-is. + result += input[i]; + } + cap_first_letter = false; + } else if ('0' <= input[i] && input[i] <= '9') { + result += input[i]; + cap_first_letter = true; + } else { + cap_first_letter = true; + } + } + // Add a trailing "_" if the name should be altered. + if (input[input.size() - 1] == '#') { + result += '_'; + } + return result; +} + +std::string EscapeDollor(const string& to_escape) { + return StringReplace(to_escape, "$", "\\$", true); +} + +std::string BinaryToHex(const string& src) { + string dest; + size_t i; + unsigned char symbol[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f', + }; + + dest.resize(src.size() * 2); + char* append_ptr = &dest[0]; + + for (i = 0; i < src.size(); i++) { + *append_ptr++ = symbol[(src[i] & 0xf0) >> 4]; + *append_ptr++ = symbol[src[i] & 0x0f]; + } + + return dest; +} + +void Indent(google::protobuf::io::Printer* printer) { + printer->Indent(); + printer->Indent(); +} +void Outdent(google::protobuf::io::Printer* printer) { + printer->Outdent(); + printer->Outdent(); +} + +void GenerateField(const google::protobuf::FieldDescriptor* field, + google::protobuf::io::Printer* printer, bool is_descriptor) { + if (field->is_repeated()) { + printer->Print( + "private $@name@;\n", + "name", field->name()); + } else if (field->containing_oneof()) { + // Oneof fields are handled by GenerateOneofField. + return; + } else { + printer->Print( + "private $@name@ = @default@;\n", + "name", field->name(), + "default", DefaultForField(field)); + } + + if (is_descriptor) { + printer->Print( + "private $has_@name@ = false;\n", + "name", field->name()); + } +} + +void GenerateOneofField(const google::protobuf::OneofDescriptor* oneof, + google::protobuf::io::Printer* printer) { + // Oneof property needs to be protected in order to be accessed by parent + // class in implementation. + printer->Print( + "protected $@name@;\n", + "name", oneof->name()); +} + +void GenerateFieldAccessor(const google::protobuf::FieldDescriptor* field, + bool is_descriptor, + google::protobuf::io::Printer* printer) { + const OneofDescriptor* oneof = field->containing_oneof(); + + // Generate getter. + if (oneof != NULL) { + printer->Print( + "public function get@camel_name@()\n" + "{\n" + " return $this->readOneof(@number@);\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "number", IntToString(field->number())); + } else { + printer->Print( + "public function get@camel_name@()\n" + "{\n" + " return $this->@name@;\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), "name", + field->name()); + } + + // Generate setter. + printer->Print( + "public function set@camel_name@(@var@)\n" + "{\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "var", (field->is_repeated() || + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? + "&$var": "$var"); + + Indent(printer); + + // Type check. + if (field->is_map()) { + } else if (field->is_repeated()) { + printer->Print( + "GPBUtil::checkRepeatedField($var, GPBType::@type@", + "type", ToUpper(field->type_name())); + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + ", \\@class_name@);\n", + "class_name", + MessageName(field->message_type(), is_descriptor) + "::class"); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer->Print( + ", @class_name@);\n", + "class_name", + EnumName(field->enum_type(), is_descriptor) + "::class"); + } else { + printer->Print(");\n"); + } + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + "GPBUtil::checkMessage($var, \\@class_name@::class);\n", + "class_name", MessageName(field->message_type(), is_descriptor)); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer->Print( + "GPBUtil::checkEnum($var, \\@class_name@::class);\n", + "class_name", EnumName(field->enum_type(), is_descriptor)); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + printer->Print( + "GPBUtil::checkString($var, @utf8@);\n", + "utf8", + field->type() == FieldDescriptor::TYPE_STRING ? "True": "False"); + } else { + printer->Print( + "GPBUtil::check@type@($var);\n", + "type", UnderscoresToCamelCase(field->cpp_type_name(), true)); + } + + if (oneof != NULL) { + printer->Print( + "$this->writeOneof(@number@, $var);\n", + "number", IntToString(field->number())); + } else { + printer->Print( + "$this->@name@ = $var;\n", + "name", field->name()); + } + + // Set has bit for proto2 only. + if (is_descriptor) { + printer->Print( + "$this->has_@field_name@ = true;\n", + "field_name", field->name()); + } + + Outdent(printer); + + printer->Print( + "}\n\n"); + + // Generate has method for proto2 only. + if (is_descriptor) { + printer->Print( + "public function has@camel_name@()\n" + "{\n" + " return $this->has_@field_name@;\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "field_name", field->name()); + } +} + +void GenerateRepeatedFieldDecode( + const google::protobuf::FieldDescriptor* field, + google::protobuf::io::Printer* printer) { + printer->Print( + "if ($input->read@cap_wire_type@($var)) return False;\n" + "$this->get@cap_field_name@() []= $var;\n", + "cap_field_name", UnderscoresToCamelCase(field->name(), true), + "cap_wire_type", UnderscoresToCamelCase(field->type_name(), true)); +} + +void GeneratePrimitiveFieldDecode( + const google::protobuf::FieldDescriptor* field, + google::protobuf::io::Printer* printer) { + printer->Print( + "if ($input->read@cap_wire_type@($var)) return False;\n" + "$this->set@cap_field_name@($var);\n", + "cap_field_name", UnderscoresToCamelCase(field->name(), true), + "cap_wire_type", UnderscoresToCamelCase(field->type_name(), true)); +} + +void GenerateFieldDecode(const google::protobuf::FieldDescriptor* field, + google::protobuf::io::Printer* printer) { + printer->Print( + "case @number@:\n", + "number", IntToString(field->number())); + Indent(printer); + + if (field->is_repeated()) { + GenerateRepeatedFieldDecode(field, printer); + } else { + GeneratePrimitiveFieldDecode(field, printer); + } + + printer->Print( + "break;\n"); + Outdent(printer); +} + +void GenerateMessage(const string& name_prefix, + const google::protobuf::Descriptor* message, + bool is_descriptor, + google::protobuf::io::Printer* printer) { + // Don't generate MapEntry messages -- we use the PHP extension's native + // support for map fields instead. + if (message->options().map_entry()) { + return; + } + + string message_name = name_prefix.empty()? + message->name() : name_prefix + "_" + message->name(); + + printer->Print( + "class @name@ extends \\Google\\Protobuf\\Internal\\Message\n" + "{\n", + "name", message_name); + Indent(printer); + + // Field and oneof definitions. + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + GenerateField(field, printer, is_descriptor); + } + for (int i = 0; i < message->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = message->oneof_decl(i); + GenerateOneofField(oneof, printer); + } + printer->Print("\n"); + + // Field and oneof accessors. + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + GenerateFieldAccessor(field, is_descriptor, printer); + } + for (int i = 0; i < message->oneof_decl_count(); i++) { + const google::protobuf::OneofDescriptor* oneof = message->oneof_decl(i); + printer->Print( + "public function get@camel_name@()\n" + "{\n" + " return $this->@name@;\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(oneof->name(), true), "name", + oneof->name()); + } + + Outdent(printer); + printer->Print("}\n\n"); + + // Nested messages and enums. + for (int i = 0; i < message->nested_type_count(); i++) { + GenerateMessage(message_name, message->nested_type(i), is_descriptor, + printer); + } + for (int i = 0; i < message->enum_type_count(); i++) { + GenerateEnum(message->enum_type(i), printer); + } +} + +void GenerateEnumToPool(const google::protobuf::EnumDescriptor* en, + bool is_descriptor, + google::protobuf::io::Printer* printer) { + printer->Print( + "$pool->addEnum('@name@', @class_name@::class)\n", + "name", EnumFullName(en, is_descriptor), + "class_name", en->name()); + Indent(printer); + + for (int i = 0; i < en->value_count(); i++) { + const EnumValueDescriptor* value = en->value(i); + printer->Print( + "->value(\"@name@\", @number@)\n", + "name", value->name(), + "number", IntToString(value->number())); + } + printer->Print("->finalizeToPool();\n\n"); + Outdent(printer); +} + +void GenerateMessageToPool(const string& name_prefix, + const google::protobuf::Descriptor* message, + bool is_descriptor, + google::protobuf::io::Printer* printer) { + // Don't generate MapEntry messages -- we use the PHP extension's native + // support for map fields instead. + if (message->options().map_entry()) { + return; + } + string class_name = name_prefix.empty()? + message->name() : name_prefix + "_" + message->name(); + + printer->Print( + "$pool->addMessage('@message@', @class_name@::class)\n", + "message", MessageFullName(message, is_descriptor), + "class_name", class_name); + + Indent(printer); + + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + if (field->is_map()) { + const FieldDescriptor* key = + field->message_type()->FindFieldByName("key"); + const FieldDescriptor* val = + field->message_type()->FindFieldByName("value"); + printer->Print( + "->map('@field@', GPBType::@key@, " + "GPBType::@value@, @number@@other@)\n", + "field", field->name(), + "key", ToUpper(key->type_name()), + "value", ToUpper(val->type_name()), + "number", SimpleItoa(field->number()), + "other", EnumOrMessageSuffix(val, is_descriptor)); + } else if (!field->containing_oneof()) { + printer->Print( + "->@label@('@field@', GPBType::@type@, @number@@other@)\n", + "field", field->name(), + "label", LabelForField(field), + "type", ToUpper(field->type_name()), + "number", SimpleItoa(field->number()), + "other", EnumOrMessageSuffix(field, is_descriptor)); + } + } + + // oneofs. + for (int i = 0; i < message->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = message->oneof_decl(i); + printer->Print("->oneof(@name@)\n", + "name", oneof->name()); + Indent(printer); + for (int index = 0; index < oneof->field_count(); index++) { + const FieldDescriptor* field = oneof->field(index); + printer->Print( + "->value('@field@', GPBType::@type@, @number@@other@)\n", + "field", field->name(), + "type", ToUpper(field->type_name()), + "number", SimpleItoa(field->number()), + "other", EnumOrMessageSuffix(field, is_descriptor)); + } + printer->Print("->finish()\n"); + Outdent(printer); + } + + printer->Print( + "->finalizeToPool();\n"); + + Outdent(printer); + + printer->Print( + "\n"); + + for (int i = 0; i < message->nested_type_count(); i++) { + GenerateMessageToPool(class_name, message->nested_type(i), is_descriptor, + printer); + } + for (int i = 0; i < message->enum_type_count(); i++) { + GenerateEnumToPool(message->enum_type(i), is_descriptor, printer); + } +} + +void GenerateAddFileToPool(const google::protobuf::FileDescriptor* file, + bool is_descriptor, + google::protobuf::io::Printer* printer) { + if (is_descriptor) { + printer->Print("$pool = DescriptorPool::getGeneratedPool();\n\n"); + + for (int i = 0; i < file->message_type_count(); i++) { + GenerateMessageToPool("", file->message_type(i), is_descriptor, printer); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnumToPool(file->enum_type(i), is_descriptor, printer); + } + + printer->Print( + "$pool->finish();\n"); + } else { + // Add messages and enums to descriptor pool. + printer->Print("$pool = DescriptorPool::getGeneratedPool();\n\n"); + + FileDescriptorSet files; + FileDescriptorProto* file_proto = files.add_file(); + file->CopyTo(file_proto); + string files_data; + files.SerializeToString(&files_data); + + printer->Print("$pool->internalAddGeneratedFile(hex2bin(\n"); + Indent(printer); + + // Only write 30 bytes per line. + static const int kBytesPerLine = 30; + for (int i = 0; i < files_data.size(); i += kBytesPerLine) { + printer->Print( + "\"@data@\"@dot@\n", + "data", BinaryToHex(files_data.substr(i, kBytesPerLine)), + "dot", i + kBytesPerLine < files_data.size() ? " ." : ""); + } + + Outdent(printer); + printer->Print( + "));\n\n"); + } + +} + +void GenerateEnum(const google::protobuf::EnumDescriptor* en, + google::protobuf::io::Printer* printer) { + printer->Print( + "class @name@\n" + "{\n", + "name", EnumClassName(en)); + Indent(printer); + + for (int i = 0; i < en->value_count(); i++) { + const EnumValueDescriptor* value = en->value(i); + printer->Print("const @name@ = @number@;\n", + "name", value->name(), + "number", IntToString(value->number())); + } + Outdent(printer); + printer->Print("}\n\n"); +} + +void GenerateUseDeclaration(bool is_descriptor, + google::protobuf::io::Printer* printer) { + if (!is_descriptor) { + printer->Print( + "use Google\\Protobuf\\Internal\\DescriptorPool;\n" + "use Google\\Protobuf\\Internal\\GPBType;\n" + "use Google\\Protobuf\\Internal\\RepeatedField;\n" + "use Google\\Protobuf\\Internal\\GPBUtil;\n\n"); + } else { + printer->Print( + "use Google\\Protobuf\\Internal\\DescriptorPool;\n" + "use Google\\Protobuf\\Internal\\GPBType;\n" + "use Google\\Protobuf\\Internal\\GPBWire;\n" + "use Google\\Protobuf\\Internal\\RepeatedField;\n" + "use Google\\Protobuf\\Internal\\InputStream;\n\n" + "use Google\\Protobuf\\Internal\\GPBUtil;\n\n"); + } +} + +void GenerateFile(const google::protobuf::FileDescriptor* file, + bool is_descriptor, google::protobuf::io::Printer* printer) { + printer->Print( + "<?php\n" + "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "# source: @filename@\n" + "\n", + "filename", file->name()); + if (!file->package().empty()) { + printer->Print("namespace @name@;\n\n", + "name", PhpName(file->package(), is_descriptor)); + } + + for (int i = 0; i < file->dependency_count(); i++) { + const std::string& name = file->dependency(i)->name(); + printer->Print("require_once('@name@');\n", "name", + GeneratedFileName(name, is_descriptor)); + } + + GenerateUseDeclaration(is_descriptor, printer); + + for (int i = 0; i < file->message_type_count(); i++) { + GenerateMessage("", file->message_type(i), is_descriptor, printer); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnum(file->enum_type(i), printer); + } + + GenerateAddFileToPool(file, is_descriptor, printer); +} + +bool Generator::Generate( + const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const { + bool is_descriptor = parameter == "internal"; + + if (is_descriptor && file->name() != kDescriptorFile) { + *error = + "Can only generate PHP code for google/protobuf/descriptor.proto.\n"; + return false; + } + + if (!is_descriptor && file->syntax() != FileDescriptor::SYNTAX_PROTO3) { + *error = + "Can only generate PHP code for proto3 .proto files.\n" + "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n"; + return false; + } + + std::string filename = GeneratedFileName(file->name(), is_descriptor); + scoped_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '@'); + + GenerateFile(file, is_descriptor, &printer); + + return true; +} + +} // namespace php +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/php/php_generator.h b/src/google/protobuf/compiler/php/php_generator.h new file mode 100644 index 00000000..ce2b000a --- /dev/null +++ b/src/google/protobuf/compiler/php/php_generator.h @@ -0,0 +1,57 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__ + +#include <google/protobuf/compiler/code_generator.h> + +#include <string> + +namespace google { +namespace protobuf { +namespace compiler { +namespace php { + +class LIBPROTOC_EXPORT Generator + : public google::protobuf::compiler::CodeGenerator { + virtual bool Generate( + const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const; +}; + +} // namespace php +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc index 6e258664..e929e4fb 100644 --- a/src/google/protobuf/compiler/subprocess.cc +++ b/src/google/protobuf/compiler/subprocess.cc @@ -261,12 +261,12 @@ string Subprocess::Win32ErrorMessage(DWORD error_code) { char* message; // WTF? - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error_code, 0, - (LPTSTR)&message, // NOT A BUG! - 0, NULL); + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error_code, 0, + (LPSTR)&message, // NOT A BUG! + 0, NULL); string result = message; LocalFree(message); diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 26494b6d..56c3b7fb 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -2535,7 +2535,7 @@ void DescriptorProto_ExtensionRange::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) @@ -2839,7 +2839,7 @@ void DescriptorProto_ReservedRange::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) @@ -7357,7 +7357,7 @@ void MethodDescriptorProto::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) @@ -8174,7 +8174,7 @@ void FileOptions::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) @@ -9582,7 +9582,7 @@ void MessageOptions::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) @@ -10196,7 +10196,7 @@ void FieldOptions::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) @@ -11192,7 +11192,7 @@ void EnumOptions::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) @@ -13053,7 +13053,7 @@ void UninterpretedOption::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) @@ -14941,7 +14941,7 @@ void GeneratedCodeInfo_Annotation::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc index f916000e..884f6ccb 100644 --- a/src/google/protobuf/duration.pb.cc +++ b/src/google/protobuf/duration.pb.cc @@ -185,7 +185,7 @@ void Duration::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) diff --git a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h index a0116a60..7314ee4f 100644 --- a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h +++ b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h @@ -128,6 +128,24 @@ inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, return old_value; } +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return __atomic_add_fetch(ptr, increment, __ATOMIC_RELAXED); +} + +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { + __atomic_store_n(ptr, value, __ATOMIC_RELAXED); +} + +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED); +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return __atomic_load_n(ptr, __ATOMIC_RELAXED); +} + #endif // defined(__LP64__) } // namespace internal diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h index 87271c5e..bbd507a8 100644 --- a/src/google/protobuf/stubs/callback.h +++ b/src/google/protobuf/stubs/callback.h @@ -381,6 +381,8 @@ class MethodResultCallback_5_2 : public ResultCallback2<R, A1, A2> { typename remove_reference<P5>::type p5_; }; +} // namespace internal + // See Closure. inline Closure* NewCallback(void (*function)()) { return new internal::FunctionClosure0(function, true); @@ -533,8 +535,6 @@ inline ResultCallback2<R, A1, A2>* NewPermanentCallback( p2, p3, p4, p5); } -} // namespace internal - // A function which does nothing. Useful for creating no-op callbacks, e.g.: // Closure* nothing = NewCallback(&DoNothing); void LIBPROTOBUF_EXPORT DoNothing(); diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc index 25bae9b0..f9e2cfd4 100644 --- a/src/google/protobuf/stubs/common_unittest.cc +++ b/src/google/protobuf/stubs/common_unittest.cc @@ -41,8 +41,6 @@ namespace google { namespace protobuf { -using internal::NewCallback; -using internal::NewPermanentCallback; namespace { // TODO(kenton): More tests. diff --git a/src/google/protobuf/stubs/map_util.h b/src/google/protobuf/stubs/map_util.h index 4cccbbed..887f12a6 100644 --- a/src/google/protobuf/stubs/map_util.h +++ b/src/google/protobuf/stubs/map_util.h @@ -208,7 +208,7 @@ typename Collection::value_type::second_type::element_type& FindLinkedPtrOrDie(const Collection& collection, const typename Collection::value_type::first_type& key) { typename Collection::const_iterator it = collection.find(key); - CHECK(it != collection.end()) << "key not found: " << key; + GOOGLE_CHECK(it != collection.end()) << "key not found: " << key; // Since linked_ptr::operator*() is a const member returning a non const, // we do not need a version of this function taking a non const collection. return *it->second; @@ -337,14 +337,15 @@ bool InsertIfNotPresent( template <class Collection> void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) { - CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value; + GOOGLE_CHECK(InsertIfNotPresent(collection, value)) + << "duplicate value: " << value; } // Same as above except doesn't log the value on error. template <class Collection> void InsertOrDieNoPrint(Collection* const collection, const typename Collection::value_type& value) { - CHECK(InsertIfNotPresent(collection, value)) << "duplicate value."; + GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value."; } // Inserts the key-value pair into the collection. Dies if key was already diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc index 37def58d..d5f7779e 100644 --- a/src/google/protobuf/stubs/once_unittest.cc +++ b/src/google/protobuf/stubs/once_unittest.cc @@ -43,7 +43,6 @@ namespace google { namespace protobuf { -using internal::NewCallback; namespace { class OnceInitTest : public testing::Test { @@ -128,11 +127,11 @@ class OnceInitTest : public testing::Test { }; TestThread* RunInitOnceInNewThread() { - return new TestThread(internal::NewCallback(this, &OnceInitTest::InitOnce)); + return new TestThread(NewCallback(this, &OnceInitTest::InitOnce)); } TestThread* RunInitRecursiveOnceInNewThread() { return new TestThread( - internal::NewCallback(this, &OnceInitTest::InitRecursiveOnce)); + NewCallback(this, &OnceInitTest::InitRecursiveOnce)); } enum State { diff --git a/src/google/protobuf/stubs/substitute.cc b/src/google/protobuf/stubs/substitute.cc index c9d95899..7194a5b1 100644 --- a/src/google/protobuf/stubs/substitute.cc +++ b/src/google/protobuf/stubs/substitute.cc @@ -113,7 +113,9 @@ void SubstituteAndAppend( for (int i = 0; format[i] != '\0'; i++) { if (format[i] == '$') { if (ascii_isdigit(format[i+1])) { - const SubstituteArg* src = args_array[format[i+1] - '0']; + unsigned int index = format[i+1] - '0'; + assert(index < 10); + const SubstituteArg* src = args_array[index]; memcpy(target, src->data(), src->size()); target += src->size(); ++i; // Skip next char. diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc index 3d07b127..470512ed 100644 --- a/src/google/protobuf/testing/file.cc +++ b/src/google/protobuf/testing/file.cc @@ -91,6 +91,7 @@ bool File::WriteStringToFile(const string& contents, const string& name) { if (fwrite(contents.data(), 1, contents.size(), file) != contents.size()) { GOOGLE_LOG(ERROR) << "fwrite(" << name << "): " << strerror(errno); + fclose(file); return false; } @@ -140,12 +141,12 @@ void File::DeleteRecursively(const string& name, #ifdef _MSC_VER // This interface is so weird. - WIN32_FIND_DATA find_data; - HANDLE find_handle = FindFirstFile((name + "/*").c_str(), &find_data); + WIN32_FIND_DATAA find_data; + HANDLE find_handle = FindFirstFileA((name + "/*").c_str(), &find_data); if (find_handle == INVALID_HANDLE_VALUE) { // Just delete it, whatever it is. - DeleteFile(name.c_str()); - RemoveDirectory(name.c_str()); + DeleteFileA(name.c_str()); + RemoveDirectoryA(name.c_str()); return; } @@ -155,15 +156,15 @@ void File::DeleteRecursively(const string& name, string path = name + "/" + entry_name; if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { DeleteRecursively(path, NULL, NULL); - RemoveDirectory(path.c_str()); + RemoveDirectoryA(path.c_str()); } else { - DeleteFile(path.c_str()); + DeleteFileA(path.c_str()); } } - } while(FindNextFile(find_handle, &find_data)); + } while(FindNextFileA(find_handle, &find_data)); FindClose(find_handle); - RemoveDirectory(name.c_str()); + RemoveDirectoryA(name.c_str()); #else // Use opendir()! Yay! // lstat = Don't follow symbolic links. diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc index 0a18edbe..e6c9c58b 100644 --- a/src/google/protobuf/timestamp.pb.cc +++ b/src/google/protobuf/timestamp.pb.cc @@ -199,7 +199,7 @@ void Timestamp::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc index 87a7864f..fc7d5332 100644 --- a/src/google/protobuf/type.pb.cc +++ b/src/google/protobuf/type.pb.cc @@ -1126,7 +1126,7 @@ void Field::Clear() { #endif #define ZR_(first, last) do {\ - ::memset(&first, 0,\ + ::memset(&(first), 0,\ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index 1e8dab70..3479949b 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -165,7 +165,10 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( if (current_ == NULL) { ow_->RenderBytes(name, value); } else { - RenderDataPiece(name, DataPiece(value, false, true)); + // Since StringPiece is essentially a pointer, takes a copy of "value" to + // avoid ownership issues. + string_values_.push_back(new string(value.ToString())); + RenderDataPiece(name, DataPiece(*string_values_.back(), false, true)); } return this; } @@ -583,7 +586,6 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, new Node(name.ToString(), NULL, PRIMITIVE, data, false, child == NULL ? current_->path() : child->path(), suppress_empty_list_, field_scrub_callback_.get())); - child = node.get(); current_->AddChild(node.release()); } else { child->set_data(data); diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc index 39be7b03..be51ce56 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ b/src/google/protobuf/util/internal/json_stream_parser.cc @@ -315,7 +315,6 @@ util::Status JsonStreamParser::ParseStringHelper() { // We're about to handle an escape, copy all bytes from last to data. if (last < data) { parsed_storage_.append(last, data - last); - last = data; } // If we ran out of string after the \, cancel or report an error // depending on if we expect more data later. @@ -371,7 +370,6 @@ util::Status JsonStreamParser::ParseStringHelper() { } else { if (last < data) { parsed_storage_.append(last, data - last); - last = data; } parsed_ = StringPiece(parsed_storage_); } diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index 1825f556..73e05cfe 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -907,7 +907,7 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, // conversions as much as possible. Because ToSnakeCase sometimes returns the // wrong value. google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback( - ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow)); + NewPermanentCallback(&RenderOneFieldPath, ow)); return DecodeCompactFieldMaskPaths(data.str(), callback.get()); } diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index dacac5e0..24ff5fd6 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc @@ -128,6 +128,34 @@ TEST_F(JsonUtilTest, TestDefaultValues) { "\"repeatedMessageValue\":[]" "}", ToJson(m, options)); + + options.always_print_primitive_fields = true; + m.set_string_value("i am a test string value"); + m.set_bytes_value("i am a test bytes value"); + EXPECT_EQ( + "{\"boolValue\":false," + "\"int32Value\":0," + "\"int64Value\":\"0\"," + "\"uint32Value\":0," + "\"uint64Value\":\"0\"," + "\"floatValue\":0," + "\"doubleValue\":0," + "\"stringValue\":\"i am a test string value\"," + "\"bytesValue\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\"," + "\"enumValue\":\"FOO\"," + "\"repeatedBoolValue\":[]," + "\"repeatedInt32Value\":[]," + "\"repeatedInt64Value\":[]," + "\"repeatedUint32Value\":[]," + "\"repeatedUint64Value\":[]," + "\"repeatedFloatValue\":[]," + "\"repeatedDoubleValue\":[]," + "\"repeatedStringValue\":[]," + "\"repeatedBytesValue\":[]," + "\"repeatedEnumValue\":[]," + "\"repeatedMessageValue\":[]" + "}", + ToJson(m, options)); } TEST_F(JsonUtilTest, ParseMessage) { diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index a6d0cb07..328b40d8 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -626,6 +626,7 @@ bool MessageDifferencer::CompareWithFieldsInternal( } if (reporter_ != NULL) { + assert(field1 != NULL); int count = field1->is_repeated() ? reflection1->FieldSize(message1, field1) : 1; @@ -706,6 +707,7 @@ bool MessageDifferencer::CompareWithFieldsInternal( } bool fieldDifferent = false; + assert(field1 != NULL); if (field1->is_repeated()) { fieldDifferent = !CompareRepeatedField(message1, message2, field1, parent_fields); @@ -875,6 +877,7 @@ bool MessageDifferencer::CompareRepeatedField( for (int i = 0; i < count1; ++i) { if (match_list1[i] != -1) continue; + assert(reporter_ != NULL); specific_field.index = i; parent_fields->push_back(specific_field); reporter_->ReportDeleted(message1, message2, *parent_fields); @@ -1389,8 +1392,7 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( // doesn't necessarily imply Compare(b, c). Therefore a naive greedy // algorithm will fail to find a maximum matching. // Here we use the argumenting path algorithm. - MaximumMatcher::NodeMatchCallback* callback = - ::google::protobuf::internal::NewPermanentCallback( + MaximumMatcher::NodeMatchCallback* callback = NewPermanentCallback( this, &MessageDifferencer::IsMatch, repeated_field, key_comparator, &message1, &message2, parent_fields); |