diff options
Diffstat (limited to 'src')
9 files changed, 123 insertions, 39 deletions
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc index d6f01c60..857d24a4 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc @@ -80,10 +80,12 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { // Include the unknown value. printer->Print( + "/// Value used if any message's field encounters a value that is not defined\n" + "/// by this enum. The message will also have C functions to get/set the rawValue\n" + "/// of the field.\n" "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n", "name", name_); } - for (int i = 0; i < all_values_.size(); i++) { SourceLocation location; if (all_values_[i]->GetSourceLocation(&location)) { @@ -107,6 +109,8 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { "\n" "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n" "\n" + "/// Checks to see if the given value is defined by the enum or was not known at\n" + "/// the time this source was generated.\n" "BOOL $name$_IsValidValue(int32_t value);\n" "\n", "name", name_); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc index ecc77f6b..cfbb8c52 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc @@ -87,7 +87,12 @@ void EnumFieldGenerator::GenerateCFunctionDeclarations( printer->Print( variables_, + "/// Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even\n" + "/// if the value was not defined by the enum at the time the code was generated.\n" "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);\n" + "/// Sets the raw value of an @c $owning_message_class$'s @c $name$ property, allowing\n" + "/// it to be set to a value that was not defined by the enum at the time the code\n" + "/// was generated.\n" "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);\n" "\n"); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc index 09341820..8697e225 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -270,15 +270,15 @@ void SingleFieldGenerator::GenerateFieldStorageDeclaration( void SingleFieldGenerator::GeneratePropertyDeclaration( io::Printer* printer) const { printer->Print(variables_, "$comments$"); + printer->Print( + variables_, + "@property(nonatomic, readwrite) $property_type$ $name$;\n" + "\n"); if (WantsHasProperty()) { printer->Print( variables_, "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); } - printer->Print( - variables_, - "@property(nonatomic, readwrite) $property_type$ $name$;\n" - "\n"); } void SingleFieldGenerator::GeneratePropertyImplementation( @@ -326,14 +326,15 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration( // conventions (init*, new*, etc.) printer->Print(variables_, "$comments$"); + printer->Print( + variables_, + "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$;\n"); if (WantsHasProperty()) { printer->Print( variables_, + "/// Test to see if @c $name$ has been set.\n" "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); } - printer->Print( - variables_, - "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$;\n"); if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 @@ -385,6 +386,7 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration( "$comments$" "$array_comment$" "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$;\n" + "/// The number of items in @c $name$ without causing the array to be created.\n" "@property(nonatomic, readonly) NSUInteger $name$_Count;\n"); if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index cdf9ebbc..16199884 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -151,13 +151,15 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { printer->Print( "#pragma mark - $root_class_name$\n" "\n" + "/// Exposes the extension registry for this file.\n" + "///\n" + "/// The base class provides:\n" + "/// @code\n" + "/// + (GPBExtensionRegistry *)extensionRegistry;\n" + "/// @endcode\n" + "/// which is a @c GPBExtensionRegistry that includes all the extensions defined by\n" + "/// this file and all files that it depends on.\n" "@interface $root_class_name$ : GPBRootObject\n" - "\n" - "// The base class provides:\n" - "// + (GPBExtensionRegistry *)extensionRegistry;\n" - "// which is an GPBExtensionRegistry that includes all the extensions defined by\n" - "// this file and all files that it depends on.\n" - "\n" "@end\n" "\n", "root_class_name", root_class_name_); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index 3e7ccb43..b912ea67 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -124,9 +124,14 @@ string UnderscoresToCamelCase(const string& input, bool first_capitalized) { } values.push_back(current); + string result; + bool first_segment_forces_upper = false; for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) { string value = *i; bool all_upper = (kUpperSegments.count(value) > 0); + if (all_upper && (result.length() == 0)) { + first_segment_forces_upper = true; + } for (int j = 0; j < value.length(); j++) { if (j == 0 || all_upper) { value[j] = ascii_toupper(value[j]); @@ -134,13 +139,11 @@ string UnderscoresToCamelCase(const string& input, bool first_capitalized) { // Nothing, already in lower. } } - *i = value; - } - string result; - for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) { - result += *i; + result += value; } - if ((result.length() != 0) && !first_capitalized) { + if ((result.length() != 0) && + !first_capitalized && + !first_segment_forces_upper) { result[0] = ascii_tolower(result[0]); } return result; @@ -771,16 +774,14 @@ string BuildCommentsString(const SourceLocation& location) { while (!lines.empty() && lines.back().empty()) { lines.pop_back(); } - string prefix("//"); + string prefix("///"); string suffix("\n"); string final_comments; for (int i = 0; i < lines.size(); i++) { - // We use $ for delimiters, so replace comments with dollars with - // html escaped version. - // None of the other compilers handle this (as of this writing) but we - // ran into it once, so just to be safe. + // HeaderDoc uses '\' and '@' for markers; escape them. + const string line = StringReplace(lines[i], "\\", "\\\\", true); final_comments += - prefix + StringReplace(lines[i], "$", "$", true) + suffix; + prefix + StringReplace(line, "@", "\\@", true) + suffix; } return final_comments; } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index 5b2dd190..a301493e 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -146,6 +146,7 @@ string DefaultValue(const FieldDescriptor* field); string BuildFlagsString(const vector<string>& strings); +// Builds a HeaderDoc style comment out of the comments in the .proto file. string BuildCommentsString(const SourceLocation& location); // Checks the prefix for a given file and outputs any warnings needed, if diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc index 3cb87482..24e6df07 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc @@ -104,6 +104,7 @@ void OneofGenerator::GeneratePublicCasePropertyDeclaration( void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) { printer->Print( variables_, + "/// Clears whatever value was set for the oneof '$name$'.\n" "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n"); } diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc index 9692f1bf..92c76fb0 100644 --- a/src/google/protobuf/compiler/ruby/ruby_generator.cc +++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc @@ -75,6 +75,10 @@ std::string StripDotProto(const std::string& proto_file) { return proto_file.substr(0, lastindex); } +std::string GetOutputFilename(const std::string& proto_file) { + return StripDotProto(proto_file) + ".rb"; +} + std::string LabelForField(const google::protobuf::FieldDescriptor* field) { switch (field->label()) { case FieldDescriptor::LABEL_OPTIONAL: return "optional"; @@ -331,8 +335,69 @@ void EndPackageModules( } } -void GenerateFile(const google::protobuf::FileDescriptor* file, - google::protobuf::io::Printer* printer) { +bool UsesTypeFromFile(const Descriptor* message, const FileDescriptor* file, + string* error) { + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + field->message_type()->file() == file) || + (field->type() == FieldDescriptor::TYPE_ENUM && + field->enum_type()->file() == file)) { + *error = "proto3 message field " + field->full_name() + " in file " + + file->name() + " has a dependency on a type from proto2 file " + + file->name() + + ". Ruby doesn't support proto2 yet, so we must fail."; + return true; + } + } + + for (int i = 0; i < message->nested_type_count(); i++) { + if (UsesTypeFromFile(message->nested_type(i), file, error)) { + return true; + } + } + + return false; +} + +// Ruby doesn't currently support proto2. This causes a failure even for proto3 +// files that import proto2. But in some cases, the proto2 file is only being +// imported to extend another proto2 message. The prime example is declaring +// custom options by extending FileOptions/FieldOptions/etc. +// +// If the proto3 messages don't have any proto2 submessages, it is safe to omit +// the dependency completely. Users won't be able to use any proto2 extensions, +// but they already couldn't because proto2 messages aren't supported. +// +// If/when we add proto2 support, we should remove this. +bool MaybeEmitDependency(const FileDescriptor* import, + const FileDescriptor* from, + io::Printer* printer, + string* error) { + if (import->syntax() == FileDescriptor::SYNTAX_PROTO2) { + for (int i = 0; i < from->message_type_count(); i++) { + if (UsesTypeFromFile(from->message_type(i), import, error)) { + // Error text was already set by UsesTypeFromFile(). + return false; + } + } + + // Ok to omit this proto2 dependency -- so we won't print anything. + GOOGLE_LOG(WARNING) << "Omitting proto2 dependency '" << import->name() + << "' from proto3 output file '" + << GetOutputFilename(from->name()) + << "' because we don't support proto2 and no proto2 " + "types from that file are being used."; + return true; + } else { + printer->Print( + "require '$name$'\n", "name", StripDotProto(import->name())); + return true; + } +} + +bool GenerateFile(const FileDescriptor* file, io::Printer* printer, + string* error) { printer->Print( "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" "# source: $filename$\n" @@ -343,9 +408,9 @@ void GenerateFile(const google::protobuf::FileDescriptor* file, "require 'google/protobuf'\n\n"); for (int i = 0; i < file->dependency_count(); i++) { - const std::string& name = file->dependency(i)->name(); - printer->Print( - "require '$name$'\n", "name", StripDotProto(name)); + if (!MaybeEmitDependency(file->dependency(i), file, printer, error)) { + return false; + } } printer->Print( @@ -369,6 +434,7 @@ void GenerateFile(const google::protobuf::FileDescriptor* file, GenerateEnumAssignment("", file->enum_type(i), printer); } EndPackageModules(levels, printer); + return true; } bool Generator::Generate( @@ -384,15 +450,11 @@ bool Generator::Generate( return false; } - std::string filename = - StripDotProto(file->name()) + ".rb"; scoped_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(filename)); + generator_context->Open(GetOutputFilename(file->name()))); io::Printer printer(output.get(), '$'); - GenerateFile(file, &printer); - - return true; + return GenerateFile(file, &printer, error); } } // namespace ruby diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index dfc62420..83199380 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -545,10 +545,16 @@ class Map { } #if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \ - !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID) + !defined(GOOGLE_PROTOBUF_OS_NACL) && \ + !defined(GOOGLE_PROTOBUF_OS_ANDROID) && \ + !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN) template<class NodeType, class... Args> void construct(NodeType* p, Args&&... args) { - new (static_cast<void*>(p)) NodeType(std::forward<Args>(args)...); + // Clang 3.6 doesn't compile static casting to void* directly. (Issue #1266) + // According C++ standard 5.2.9/1: "The static_cast operator shall not cast + // away constness". So first the maybe const pointer is casted to const void* and + // after the const void* is const casted. + new (const_cast<void*>(static_cast<const void*>(p))) NodeType(std::forward<Args>(args)...); } template<class NodeType> |