aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am8
-rw-r--r--csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs13
-rwxr-xr-xgenerate_descriptor_proto.sh2
-rwxr-xr-xobjectivec/DevTools/compile_testing_protos.sh71
-rw-r--r--objectivec/GPBArray.m20
-rw-r--r--objectivec/GPBBootstrap.h2
-rw-r--r--objectivec/GPBCodedOutputStream.m2
-rw-r--r--objectivec/GPBDescriptor.h9
-rw-r--r--objectivec/GPBDescriptor.m114
-rw-r--r--objectivec/GPBDescriptor_PackagePrivate.h8
-rw-r--r--objectivec/GPBWellKnownTypes.h141
-rw-r--r--objectivec/GPBWellKnownTypes.m135
-rw-r--r--objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj6
-rw-r--r--objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj6
-rw-r--r--objectivec/Tests/GPBDescriptorTests.m29
-rw-r--r--objectivec/Tests/GPBMessageTests+Runtime.m20
-rw-r--r--objectivec/Tests/GPBUnittestProtos.m9
-rw-r--r--objectivec/Tests/GPBUnittestProtos2.m34
-rw-r--r--objectivec/Tests/GPBWellKnownTypesTest.m56
-rw-r--r--objectivec/Tests/unittest_cycle.proto6
-rw-r--r--objectivec/Tests/unittest_extension_chain_a.proto51
-rw-r--r--objectivec/Tests/unittest_extension_chain_b.proto47
-rw-r--r--objectivec/Tests/unittest_extension_chain_c.proto45
-rw-r--r--objectivec/Tests/unittest_extension_chain_d.proto49
-rw-r--r--objectivec/Tests/unittest_extension_chain_e.proto40
-rw-r--r--objectivec/Tests/unittest_extension_chain_f.proto44
-rw-r--r--objectivec/Tests/unittest_extension_chain_g.proto41
-rw-r--r--objectivec/google/protobuf/Any.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Any.pbobjc.m8
-rw-r--r--objectivec/google/protobuf/Api.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Api.pbobjc.m29
-rw-r--r--objectivec/google/protobuf/Duration.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Duration.pbobjc.m6
-rw-r--r--objectivec/google/protobuf/Empty.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Empty.pbobjc.m6
-rw-r--r--objectivec/google/protobuf/FieldMask.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/FieldMask.pbobjc.m6
-rw-r--r--objectivec/google/protobuf/SourceContext.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/SourceContext.pbobjc.m6
-rw-r--r--objectivec/google/protobuf/Struct.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Struct.pbobjc.m12
-rw-r--r--objectivec/google/protobuf/Timestamp.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Timestamp.pbobjc.m6
-rw-r--r--objectivec/google/protobuf/Type.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Type.pbobjc.m35
-rw-r--r--objectivec/google/protobuf/Wrappers.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Wrappers.pbobjc.m22
-rwxr-xr-xpython/google/protobuf/internal/reflection_test.py2
-rw-r--r--src/google/protobuf/api.pb.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc2
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_extension.cc2
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_field.cc2
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_file.cc226
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.cc72
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.h12
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_map_field.cc2
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_message.cc16
-rw-r--r--src/google/protobuf/descriptor.pb.cc18
-rw-r--r--src/google/protobuf/duration.pb.cc2
-rw-r--r--src/google/protobuf/timestamp.pb.cc2
-rw-r--r--src/google/protobuf/type.pb.cc2
-rw-r--r--src/google/protobuf/util/internal/default_value_objectwriter.cc5
-rw-r--r--src/google/protobuf/util/json_util_test.cc28
63 files changed, 1347 insertions, 212 deletions
diff --git a/Makefile.am b/Makefile.am
index 41d25823..a4de1bd3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -534,6 +534,7 @@ objectivec_EXTRA_DIST= \
objectivec/Tests/GPBTestUtilities.h \
objectivec/Tests/GPBTestUtilities.m \
objectivec/Tests/GPBUnittestProtos.m \
+ objectivec/Tests/GPBUnittestProtos2.m \
objectivec/Tests/GPBUnknownFieldSetTest.m \
objectivec/Tests/GPBUtilitiesTests.m \
objectivec/Tests/GPBWellKnownTypesTest.m \
@@ -555,6 +556,13 @@ objectivec_EXTRA_DIST= \
objectivec/Tests/text_format_map_unittest_data.txt \
objectivec/Tests/text_format_unittest_data.txt \
objectivec/Tests/unittest_cycle.proto \
+ objectivec/Tests/unittest_extension_chain_a.proto \
+ objectivec/Tests/unittest_extension_chain_b.proto \
+ objectivec/Tests/unittest_extension_chain_c.proto \
+ objectivec/Tests/unittest_extension_chain_d.proto \
+ objectivec/Tests/unittest_extension_chain_e.proto \
+ objectivec/Tests/unittest_extension_chain_f.proto \
+ objectivec/Tests/unittest_extension_chain_g.proto \
objectivec/Tests/unittest_objc.proto \
objectivec/Tests/unittest_objc_startup.proto \
objectivec/Tests/unittest_runtime_proto2.proto \
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
index ab7cd922..94efea9e 100644
--- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -251,17 +251,6 @@ namespace Google.Protobuf.Reflection
"Dependencies passed to FileDescriptor.BuildFrom() don't match " +
"those listed in the FileDescriptorProto.");
}
- for (int i = 0; i < proto.Dependency.Count; i++)
- {
- if (dependencies[i].Name != proto.Dependency[i])
- {
- throw new DescriptorValidationException(
- result,
- "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
- "those listed in the FileDescriptorProto. Expected: " +
- proto.Dependency[i] + " but was: " + dependencies[i].Name);
- }
- }
result.CrossLink();
return result;
@@ -341,4 +330,4 @@ namespace Google.Protobuf.Reflection
/// </value>
public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorReflection.Descriptor; } }
}
-} \ No newline at end of file
+}
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
index c170c837..668e6d13 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
# Run this script to regenerate descriptor.pb.{h,cc} after the protocol
# compiler changes. Since these files are compiled into the protocol compiler
diff --git a/objectivec/DevTools/compile_testing_protos.sh b/objectivec/DevTools/compile_testing_protos.sh
index 9a6b7bf2..6cc32da9 100755
--- a/objectivec/DevTools/compile_testing_protos.sh
+++ b/objectivec/DevTools/compile_testing_protos.sh
@@ -1,17 +1,16 @@
-#!/bin/bash
-
+#!/bin/bash -eu
# Invoked by the Xcode projects to build the protos needed for the unittests.
-set -eu
-
readonly OUTPUT_DIR="${PROJECT_DERIVED_FILE_DIR}/protos"
+# -----------------------------------------------------------------------------
# Helper for bailing.
die() {
echo "Error: $1"
exit 2
}
+# -----------------------------------------------------------------------------
# What to do.
case "${ACTION}" in
"")
@@ -26,12 +25,19 @@ case "${ACTION}" in
;;
esac
-# Move to the top of the protobuf directories.
-cd "${SRCROOT}/.."
+# -----------------------------------------------------------------------------
+# Ensure the output dir exists
+mkdir -p "${OUTPUT_DIR}/google/protobuf"
+# -----------------------------------------------------------------------------
+# Move to the top of the protobuf directories and ensure there is a protoc
+# binary to use.
+cd "${SRCROOT}/.."
[[ -x src/protoc ]] || \
die "Could not find the protoc binary; make sure you have built it (objectivec/DevTools/full_mac_build.sh -h)."
+# -----------------------------------------------------------------------------
+# See the compiler or proto files have changed.
RUN_PROTOC=no
if [[ ! -d "${OUTPUT_DIR}" ]] ; then
RUN_PROTOC=yes
@@ -50,7 +56,7 @@ else
# Find the oldest output file.
readonly OldestOutput=$(find \
"${OUTPUT_DIR}" \
- -type f -print0 \
+ -type f -name "*pbobjc.[hm]" -print0 \
| xargs -0 stat -f "%m %N" \
| sort -n -r | tail -n1 | cut -f2- -d" ")
# If the newest input is newer than the oldest output, regenerate.
@@ -64,10 +70,30 @@ if [[ "${RUN_PROTOC}" != "yes" ]] ; then
exit 0
fi
-# Ensure the output dir exists
-mkdir -p "${OUTPUT_DIR}/google/protobuf"
+# -----------------------------------------------------------------------------
+# Prune out all the files from previous generations to ensure we only have
+# current ones.
+find "${OUTPUT_DIR}" \
+ -type f -name "*pbobjc.[hm]" -print0 \
+ | xargs -0 rm -rf
+
+# -----------------------------------------------------------------------------
+# Helper to invoke protoc
+compile_protos() {
+ src/protoc \
+ --objc_out="${OUTPUT_DIR}/google/protobuf" \
+ --proto_path=src/google/protobuf/ \
+ --proto_path=src \
+ "$@"
+}
+
+# -----------------------------------------------------------------------------
+# Generate most of the proto files that exist in the C++ src tree. Several
+# are used in the tests, but the extra don't hurt in that they ensure ObjC
+# sources can be generated from them.
CORE_PROTO_FILES=(
+ src/google/protobuf/any_test.proto
src/google/protobuf/unittest_arena.proto
src/google/protobuf/unittest_custom_options.proto
src/google/protobuf/unittest_enormous_descriptor.proto
@@ -90,23 +116,12 @@ CORE_PROTO_FILES=(
src/google/protobuf/map_lite_unittest.proto
src/google/protobuf/map_proto2_unittest.proto
src/google/protobuf/map_unittest.proto
-)
-
-# The unittest_custom_options.proto extends the messages in descriptor.proto
-# so we build it in to test extending in general. The library doesn't provide
-# a descriptor as it doesn't use the classes/enums.
-CORE_PROTO_FILES+=(
+ # The unittest_custom_options.proto extends the messages in descriptor.proto
+ # so we build it in to test extending in general. The library doesn't provide
+ # a descriptor as it doesn't use the classes/enums.
src/google/protobuf/descriptor.proto
)
-compile_protos() {
- src/protoc \
- --objc_out="${OUTPUT_DIR}/google/protobuf" \
- --proto_path=src/google/protobuf/ \
- --proto_path=src \
- "$@"
-}
-
# Note: there is overlap in package.Message names between some of the test
# files, so they can't be generated all at once. This works because the overlap
# isn't linked into a single binary.
@@ -114,10 +129,18 @@ for a_proto in "${CORE_PROTO_FILES[@]}" ; do
compile_protos "${a_proto}"
done
-# Objective C specific testing protos.
+# -----------------------------------------------------------------------------
+# Generate the Objective C specific testing protos.
compile_protos \
--proto_path="objectivec/Tests" \
objectivec/Tests/unittest_cycle.proto \
+ objectivec/Tests/unittest_extension_chain_a.proto \
+ objectivec/Tests/unittest_extension_chain_b.proto \
+ objectivec/Tests/unittest_extension_chain_c.proto \
+ objectivec/Tests/unittest_extension_chain_d.proto \
+ objectivec/Tests/unittest_extension_chain_e.proto \
+ objectivec/Tests/unittest_extension_chain_f.proto \
+ objectivec/Tests/unittest_extension_chain_g.proto \
objectivec/Tests/unittest_runtime_proto2.proto \
objectivec/Tests/unittest_runtime_proto3.proto \
objectivec/Tests/unittest_objc.proto \
diff --git a/objectivec/GPBArray.m b/objectivec/GPBArray.m
index 64869bbb..ae57747d 100644
--- a/objectivec/GPBArray.m
+++ b/objectivec/GPBArray.m
@@ -195,7 +195,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
//%}
//%
//%- (void)enumerate##ACCESSOR_NAME##ValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block {
-//% [self enumerate##ACCESSOR_NAME##ValuesWithOptions:0 usingBlock:block];
+//% [self enumerate##ACCESSOR_NAME##ValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
//%}
//%
//%- (void)enumerate##ACCESSOR_NAME##ValuesWithOptions:(NSEnumerationOptions)opts
@@ -406,7 +406,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
- [self enumerateValuesWithOptions:0 usingBlock:block];
+ [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -654,7 +654,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateValuesWithBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block {
- [self enumerateValuesWithOptions:0 usingBlock:block];
+ [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -902,7 +902,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateValuesWithBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block {
- [self enumerateValuesWithOptions:0 usingBlock:block];
+ [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -1150,7 +1150,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateValuesWithBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block {
- [self enumerateValuesWithOptions:0 usingBlock:block];
+ [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -1398,7 +1398,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateValuesWithBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block {
- [self enumerateValuesWithOptions:0 usingBlock:block];
+ [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -1646,7 +1646,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateValuesWithBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block {
- [self enumerateValuesWithOptions:0 usingBlock:block];
+ [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -1894,7 +1894,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateValuesWithBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block {
- [self enumerateValuesWithOptions:0 usingBlock:block];
+ [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -2166,7 +2166,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateRawValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
- [self enumerateRawValuesWithOptions:0 usingBlock:block];
+ [self enumerateRawValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts
@@ -2218,7 +2218,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
}
- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
- [self enumerateValuesWithOptions:0 usingBlock:block];
+ [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
}
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h
index 2e5bdc71..7dc943d4 100644
--- a/objectivec/GPBBootstrap.h
+++ b/objectivec/GPBBootstrap.h
@@ -99,4 +99,4 @@
// regenerated.
//
// Meant to be used internally by generated code.
-#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30001
+#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30002
diff --git a/objectivec/GPBCodedOutputStream.m b/objectivec/GPBCodedOutputStream.m
index 251a159c..7c3ab447 100644
--- a/objectivec/GPBCodedOutputStream.m
+++ b/objectivec/GPBCodedOutputStream.m
@@ -290,7 +290,7 @@ static void GPBWriteRawLittleEndian64(GPBOutputBufferState *state,
maxLength:bufferBytesLeft
usedLength:&usedBufferLength
encoding:NSUTF8StringEncoding
- options:0
+ options:(NSStringEncodingConversionOptions)0
range:NSMakeRange(0, [value length])
remainingRange:NULL];
}
diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h
index 36fb4eae..651f4de0 100644
--- a/objectivec/GPBDescriptor.h
+++ b/objectivec/GPBDescriptor.h
@@ -81,6 +81,13 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
@property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat;
/** The class of this message. */
@property(nonatomic, readonly) Class messageClass;
+/** Containing message descriptor if this message is nested, or nil otherwise. */
+@property(readonly, nullable) GPBDescriptor *containingType;
+/**
+ * Fully qualified name for this message (package.message). Can be nil if the
+ * value is unable to be computed.
+ */
+@property(readonly, nullable) NSString *fullName;
/**
* Gets the field for the given number.
@@ -118,6 +125,8 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
/** The package declared in the proto file. */
@property(nonatomic, readonly, copy) NSString *package;
+/** The objc prefix declared in the proto file. */
+@property(nonatomic, readonly, copy, nullable) NSString *objcPrefix;
/** The syntax of the proto file. */
@property(nonatomic, readonly) GPBFileSyntax syntax;
diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m
index dccb9bc8..0753a948 100644
--- a/objectivec/GPBDescriptor.m
+++ b/objectivec/GPBDescriptor.m
@@ -42,8 +42,10 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
-// The address of this variable is used as a key for obj_getAssociatedObject.
+// The addresses of these variables are used as keys for objc_getAssociatedObject.
static const char kTextFormatExtraValueKey = 0;
+static const char kParentClassNameValueKey = 0;
+static const char kClassNameSuffixKey = 0;
// Utility function to generate selectors on the fly.
static SEL SelFromStrings(const char *prefix, const char *middle,
@@ -215,10 +217,102 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
extensionRangesCount_ = count;
}
+- (void)setupContainingMessageClassName:(const char *)msgClassName {
+ // Note: Only fetch the class here, can't send messages to it because
+ // that could cause cycles back to this class within +initialize if
+ // two messages have each other in fields (i.e. - they build a graph).
+ NSAssert(objc_getClass(msgClassName), @"Class %s not defined", msgClassName);
+ NSValue *parentNameValue = [NSValue valueWithPointer:msgClassName];
+ objc_setAssociatedObject(self, &kParentClassNameValueKey,
+ parentNameValue,
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setupMessageClassNameSuffix:(NSString *)suffix {
+ if (suffix.length) {
+ objc_setAssociatedObject(self, &kClassNameSuffixKey,
+ suffix,
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ }
+}
+
- (NSString *)name {
return NSStringFromClass(messageClass_);
}
+- (GPBDescriptor *)containingType {
+ NSValue *parentNameValue =
+ objc_getAssociatedObject(self, &kParentClassNameValueKey);
+ if (!parentNameValue) {
+ return nil;
+ }
+ const char *parentName = [parentNameValue pointerValue];
+ Class parentClass = objc_getClass(parentName);
+ NSAssert(parentClass, @"Class %s not defined", parentName);
+ return [parentClass descriptor];
+}
+
+- (NSString *)fullName {
+ NSString *className = NSStringFromClass(self.messageClass);
+ GPBFileDescriptor *file = self.file;
+ NSString *objcPrefix = file.objcPrefix;
+ if (objcPrefix && ![className hasPrefix:objcPrefix]) {
+ NSAssert(0,
+ @"Class didn't have correct prefix? (%@ - %@)",
+ className, objcPrefix);
+ return nil;
+ }
+ GPBDescriptor *parent = self.containingType;
+
+ NSString *name = nil;
+ if (parent) {
+ NSString *parentClassName = NSStringFromClass(parent.messageClass);
+ // The generator will add _Class to avoid reserved words, drop it.
+ NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
+ if (suffix) {
+ if (![parentClassName hasSuffix:suffix]) {
+ NSAssert(0,
+ @"ParentMessage class didn't have correct suffix? (%@ - %@)",
+ className, suffix);
+ return nil;
+ }
+ parentClassName =
+ [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
+ }
+ NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
+ if (![className hasPrefix:parentPrefix]) {
+ NSAssert(0,
+ @"Class didn't have the correct parent name prefix? (%@ - %@)",
+ parentPrefix, className);
+ return nil;
+ }
+ name = [className substringFromIndex:parentPrefix.length];
+ } else {
+ name = [className substringFromIndex:objcPrefix.length];
+ }
+
+ // The generator will add _Class to avoid reserved words, drop it.
+ NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
+ if (suffix) {
+ if (![name hasSuffix:suffix]) {
+ NSAssert(0,
+ @"Message class didn't have correct suffix? (%@ - %@)",
+ name, suffix);
+ return nil;
+ }
+ name = [name substringToIndex:(name.length - suffix.length)];
+ }
+
+ NSString *prefix = (parent != nil ? parent.fullName : file.package);
+ NSString *result;
+ if (prefix.length > 0) {
+ result = [NSString stringWithFormat:@"%@.%@", prefix, name];
+ } else {
+ result = name;
+ }
+ return result;
+}
+
- (id)copyWithZone:(NSZone *)zone {
#pragma unused(zone)
return [self retain];
@@ -255,13 +349,27 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
@implementation GPBFileDescriptor {
NSString *package_;
+ NSString *objcPrefix_;
GPBFileSyntax syntax_;
}
@synthesize package = package_;
+@synthesize objcPrefix = objcPrefix_;
@synthesize syntax = syntax_;
- (instancetype)initWithPackage:(NSString *)package
+ objcPrefix:(NSString *)objcPrefix
+ syntax:(GPBFileSyntax)syntax {
+ self = [super init];
+ if (self) {
+ package_ = [package copy];
+ objcPrefix_ = [objcPrefix copy];
+ syntax_ = syntax;
+ }
+ return self;
+}
+
+- (instancetype)initWithPackage:(NSString *)package
syntax:(GPBFileSyntax)syntax {
self = [super init];
if (self) {
@@ -273,6 +381,7 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
- (void)dealloc {
[package_ release];
+ [objcPrefix_ release];
[super dealloc];
}
@@ -416,6 +525,9 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
// Extra type specific data.
if (isMessage) {
const char *className = coreDesc->dataTypeSpecific.className;
+ // Note: Only fetch the class here, can't send messages to it because
+ // that could cause cycles back to this class within +initialize if
+ // two messages have each other in fields (i.e. - they build a graph).
msgClass_ = objc_getClass(className);
NSAssert(msgClass_, @"Class %s not defined", className);
} else if (dataType == GPBDataTypeEnum) {
diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h
index c20ff6b0..9173e7a2 100644
--- a/objectivec/GPBDescriptor_PackagePrivate.h
+++ b/objectivec/GPBDescriptor_PackagePrivate.h
@@ -37,6 +37,7 @@
// Describes attributes of the field.
typedef NS_OPTIONS(uint16_t, GPBFieldFlags) {
+ GPBFieldNone = 0,
// These map to standard protobuf concepts.
GPBFieldRequired = 1 << 0,
GPBFieldRepeated = 1 << 1,
@@ -111,6 +112,7 @@ typedef struct GPBMessageFieldDescriptionWithDefault {
// Describes attributes of the extension.
typedef NS_OPTIONS(uint8_t, GPBExtensionOptions) {
+ GPBExtensionNone = 0,
// These map to standard protobuf concepts.
GPBExtensionRepeated = 1 << 0,
GPBExtensionPacked = 1 << 1,
@@ -130,6 +132,7 @@ typedef struct GPBExtensionDescription {
} GPBExtensionDescription;
typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
+ GPBDescriptorInitializationFlag_None = 0,
GPBDescriptorInitializationFlag_FieldsWithDefault = 1 << 0,
GPBDescriptorInitializationFlag_WireFormat = 1 << 1,
};
@@ -165,11 +168,16 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
firstHasIndex:(int32_t)firstHasIndex;
- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
+- (void)setupContainingMessageClassName:(const char *)msgClassName;
+- (void)setupMessageClassNameSuffix:(NSString *)suffix;
@end
@interface GPBFileDescriptor ()
- (instancetype)initWithPackage:(NSString *)package
+ objcPrefix:(NSString *)objcPrefix
+ syntax:(GPBFileSyntax)syntax;
+- (instancetype)initWithPackage:(NSString *)package
syntax:(GPBFileSyntax)syntax;
@end
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h
index 96d51d9e..90d96c6f 100644
--- a/objectivec/GPBWellKnownTypes.h
+++ b/objectivec/GPBWellKnownTypes.h
@@ -37,15 +37,32 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
+ #import <Protobuf/Any.pbobjc.h>
#import <Protobuf/Duration.pbobjc.h>
#import <Protobuf/Timestamp.pbobjc.h>
#else
+ #import "google/protobuf/Any.pbobjc.h"
#import "google/protobuf/Duration.pbobjc.h"
#import "google/protobuf/Timestamp.pbobjc.h"
#endif
NS_ASSUME_NONNULL_BEGIN
+#pragma mark - Errors
+
+/** NSError domain used for errors. */
+extern NSString *const GPBWellKnownTypesErrorDomain;
+
+/** Error code for NSError with GPBWellKnownTypesErrorDomain. */
+typedef NS_ENUM(NSInteger, GPBWellKnownTypesErrorCode) {
+ /** The type_url could not be computed for the requested GPBMessage class. */
+ GPBWellKnownTypesErrorCodeFailedToComputeTypeURL = -100,
+ /** type_url in a Any doesn’t match that of the requested GPBMessage class. */
+ GPBWellKnownTypesErrorCodeTypeURLMismatch = -101,
+};
+
+#pragma mark - GPBTimestamp
+
/**
* Category for GPBTimestamp to work with standard Foundation time/date types.
**/
@@ -54,7 +71,12 @@ NS_ASSUME_NONNULL_BEGIN
/** The NSDate representation of this GPBTimestamp. */
@property(nonatomic, readwrite, strong) NSDate *date;
-/** The NSTimeInterval representation of this GPBTimestamp. */
+/**
+ * The NSTimeInterval representation of this GPBTimestamp.
+ *
+ * @note: Not all second/nanos combinations can be represented in a
+ * NSTimeInterval, so getting this could be a lossy transform.
+ **/
@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
/**
@@ -77,12 +99,19 @@ NS_ASSUME_NONNULL_BEGIN
@end
+#pragma mark - GPBDuration
+
/**
* Category for GPBDuration to work with standard Foundation time type.
**/
@interface GPBDuration (GBPWellKnownTypes)
-/** The NSTimeInterval representation of this GPBTimestamp. */
+/**
+ * The NSTimeInterval representation of this GPBDuration.
+ *
+ * @note: Not all second/nanos combinations can be represented in a
+ * NSTimeInterval, so getting this could be a lossy transform.
+ **/
@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
/**
@@ -90,10 +119,116 @@ NS_ASSUME_NONNULL_BEGIN
*
* @param timeIntervalSince1970 Time interval to configure the GPBDuration with.
*
- * @return A newly initialized GPBTimestamp.
+ * @return A newly initialized GPBDuration.
**/
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970;
@end
+#pragma mark - GPBAny
+
+/**
+ * Category for GPBAny to help work with the message within the object.
+ **/
+@interface GPBAny (GBPWellKnownTypes)
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ * This uses type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ * wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+ error:(NSError **)errorPtr;
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr Pointer to an error that will be populated if something
+ * goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+ typeURLPrefix:(nonnull NSString *)typeURLPrefix
+ error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ * wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+ error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr Pointer to an error that will be populated if something
+ * goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+ typeURLPrefix:(nonnull NSString *)typeURLPrefix
+ error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ * wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+ error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr Pointer to an error that will be populated if something
+ * goes wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+ typeURLPrefix:(nonnull NSString *)typeURLPrefix
+ error:(NSError **)errorPtr;
+
+/**
+ * Unpacks the serialized message as if it was an instance of the given class.
+ *
+ * @note When checking type_url, the base URL is not checked, only the fully
+ * qualified name.
+ *
+ * @param messageClass The class to use to deserialize the contained message.
+ * @param errorPtr Pointer to an error that will be populated if something
+ * goes wrong.
+ *
+ * @return An instance of the given class populated with the contained data, or
+ * nil on failure.
+ */
+- (nullable GPBMessage *)unpackMessageClass:(Class)messageClass
+ error:(NSError **)errorPtr;
+
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m
index 5cdd62d5..ed798a2e 100644
--- a/objectivec/GPBWellKnownTypes.m
+++ b/objectivec/GPBWellKnownTypes.m
@@ -34,6 +34,13 @@
#import "GPBWellKnownTypes.h"
+#import "GPBUtilities_PackagePrivate.h"
+
+NSString *const GPBWellKnownTypesErrorDomain =
+ GPBNSStringifySymbol(GPBWellKnownTypesErrorDomain);
+
+static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/";
+
static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds,
int32_t nanos) {
return seconds + (NSTimeInterval)nanos / 1e9;
@@ -48,6 +55,30 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
return (int32_t)nanos;
}
+static NSString *BuildTypeURL(NSString *typeURLPrefix, NSString *fullName) {
+ if (typeURLPrefix.length == 0) {
+ return fullName;
+ }
+
+ if ([typeURLPrefix hasSuffix:@"/"]) {
+ return [typeURLPrefix stringByAppendingString:fullName];
+ }
+
+ return [NSString stringWithFormat:@"%@/%@", typeURLPrefix, fullName];
+}
+
+static NSString *ParseTypeFromURL(NSString *typeURLString) {
+ NSRange range = [typeURLString rangeOfString:@"/" options:NSBackwardsSearch];
+ if ((range.location == NSNotFound) ||
+ (NSMaxRange(range) == typeURLString.length)) {
+ return nil;
+ }
+ NSString *result = [typeURLString substringFromIndex:range.location + 1];
+ return result;
+}
+
+#pragma mark - GPBTimestamp
+
@implementation GPBTimestamp (GBPWellKnownTypes)
- (instancetype)initWithDate:(NSDate *)date {
@@ -87,6 +118,8 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
@end
+#pragma mark - GPBDuration
+
@implementation GPBDuration (GBPWellKnownTypes)
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
@@ -113,3 +146,105 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
}
@end
+
+#pragma mark - GPBAny
+
+@implementation GPBAny (GBPWellKnownTypes)
+
++ (instancetype)anyWithMessage:(GPBMessage *)message
+ error:(NSError **)errorPtr {
+ return [self anyWithMessage:message
+ typeURLPrefix:kTypePrefixGoogleApisCom
+ error:errorPtr];
+}
+
++ (instancetype)anyWithMessage:(GPBMessage *)message
+ typeURLPrefix:(NSString *)typeURLPrefix
+ error:(NSError **)errorPtr {
+ return [[[self alloc] initWithMessage:message
+ typeURLPrefix:typeURLPrefix
+ error:errorPtr] autorelease];
+}
+
+- (instancetype)initWithMessage:(GPBMessage *)message
+ error:(NSError **)errorPtr {
+ return [self initWithMessage:message
+ typeURLPrefix:kTypePrefixGoogleApisCom
+ error:errorPtr];
+}
+
+- (instancetype)initWithMessage:(GPBMessage *)message
+ typeURLPrefix:(NSString *)typeURLPrefix
+ error:(NSError **)errorPtr {
+ self = [self init];
+ if (self) {
+ if (![self packWithMessage:message
+ typeURLPrefix:typeURLPrefix
+ error:errorPtr]) {
+ [self release];
+ self = nil;
+ }
+ }
+ return self;
+}
+
+- (BOOL)packWithMessage:(GPBMessage *)message
+ error:(NSError **)errorPtr {
+ return [self packWithMessage:message
+ typeURLPrefix:kTypePrefixGoogleApisCom
+ error:errorPtr];
+}
+
+- (BOOL)packWithMessage:(GPBMessage *)message
+ typeURLPrefix:(NSString *)typeURLPrefix
+ error:(NSError **)errorPtr {
+ NSString *fullName = [message descriptor].fullName;
+ if (fullName.length == 0) {
+ if (errorPtr) {
+ *errorPtr =
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+ code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
+ userInfo:nil];
+ }
+ return NO;
+ }
+ if (errorPtr) {
+ *errorPtr = nil;
+ }
+ self.typeURL = BuildTypeURL(typeURLPrefix, fullName);
+ self.value = message.data;
+ return YES;
+}
+
+- (GPBMessage *)unpackMessageClass:(Class)messageClass
+ error:(NSError **)errorPtr {
+ NSString *fullName = [messageClass descriptor].fullName;
+ if (fullName.length == 0) {
+ if (errorPtr) {
+ *errorPtr =
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+ code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
+ userInfo:nil];
+ }
+ return nil;
+ }
+
+ NSString *expectedFullName = ParseTypeFromURL(self.typeURL);
+ if ((expectedFullName == nil) || ![expectedFullName isEqual:fullName]) {
+ if (errorPtr) {
+ *errorPtr =
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+ code:GPBWellKnownTypesErrorCodeTypeURLMismatch
+ userInfo:nil];
+ }
+ return nil;
+ }
+
+ // Any is proto3, which means no extensions, so this assumes anything put
+ // within an any also won't need extensions. A second helper could be added
+ // if needed.
+ return [messageClass parseFromData:self.value
+ error:errorPtr];
+}
+
+@end
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
index 32067910..1585dbed 100644
--- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
@@ -65,6 +65,7 @@
F4E675A11B21D0000054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675911B21D0000054530B /* Struct.pbobjc.m */; };
F4E675A31B21D0000054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675931B21D0000054530B /* Type.pbobjc.m */; };
F4E675A51B21D0000054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675951B21D0000054530B /* Wrappers.pbobjc.m */; };
+ F4F8D8831D789FD9002CE128 /* GPBUnittestProtos2.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -211,6 +212,7 @@
F4E675AB1B21D05C0054530B /* struct.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = struct.proto; path = ../src/google/protobuf/struct.proto; sourceTree = "<group>"; };
F4E675AC1B21D05C0054530B /* type.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = type.proto; path = ../src/google/protobuf/type.proto; sourceTree = "<group>"; };
F4E675AD1B21D05C0054530B /* wrappers.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrappers.proto; path = ../src/google/protobuf/wrappers.proto; sourceTree = "<group>"; };
+ F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos2.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -408,6 +410,7 @@
7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */,
+ F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */,
7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */,
7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */,
8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */,
@@ -659,6 +662,7 @@
F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
F4487C7F1AAF62CD00531423 /* GPBMessageTests+Serialization.m in Sources */,
8B4248DC1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
+ F4F8D8831D789FD9002CE128 /* GPBUnittestProtos2.m in Sources */,
F4353D1D1AB8822D005A6198 /* GPBDescriptorTests.m in Sources */,
8B4248BB1A8C256A00BC1EC6 /* GPBSwiftTests.swift in Sources */,
5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
@@ -778,6 +782,7 @@
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_STATIC_ANALYZER_MODE = deep;
+ CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
@@ -838,6 +843,7 @@
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_STATIC_ANALYZER_MODE = deep;
+ CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
index 9f688f8d..b6bc95ab 100644
--- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
@@ -73,6 +73,7 @@
F4E675D51B21D1620054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C21B21D1440054530B /* Struct.pbobjc.m */; };
F4E675D61B21D1620054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C51B21D1440054530B /* Type.pbobjc.m */; };
F4E675D71B21D1620054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C71B21D1440054530B /* Wrappers.pbobjc.m */; };
+ F4F8D8861D78A193002CE128 /* GPBUnittestProtos2.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -234,6 +235,7 @@
F4E675DD1B21D1DE0054530B /* struct.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = struct.proto; path = ../src/google/protobuf/struct.proto; sourceTree = "<group>"; };
F4E675DE1B21D1DE0054530B /* type.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = type.proto; path = ../src/google/protobuf/type.proto; sourceTree = "<group>"; };
F4E675DF1B21D1DE0054530B /* wrappers.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrappers.proto; path = ../src/google/protobuf/wrappers.proto; sourceTree = "<group>"; };
+ F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos2.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -446,6 +448,7 @@
7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */,
+ F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */,
7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */,
7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */,
8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */,
@@ -755,6 +758,7 @@
F4487C811AAF62FC00531423 /* GPBMessageTests+Serialization.m in Sources */,
8B4248E61A929C9900BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
F4353D1F1AB88243005A6198 /* GPBDescriptorTests.m in Sources */,
+ F4F8D8861D78A193002CE128 /* GPBUnittestProtos2.m in Sources */,
F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */,
5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
@@ -940,6 +944,7 @@
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_STATIC_ANALYZER_MODE = deep;
+ CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
@@ -1001,6 +1006,7 @@
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_STATIC_ANALYZER_MODE = deep;
+ CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
diff --git a/objectivec/Tests/GPBDescriptorTests.m b/objectivec/Tests/GPBDescriptorTests.m
index 74e3172b..1e1c3de8 100644
--- a/objectivec/Tests/GPBDescriptorTests.m
+++ b/objectivec/Tests/GPBDescriptorTests.m
@@ -34,12 +34,41 @@
#import "GPBDescriptor.h"
#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+#import "google/protobuf/Descriptor.pbobjc.h"
@interface DescriptorTests : GPBTestCase
@end
@implementation DescriptorTests
+- (void)testDescriptor_containingType {
+ GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+ GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+ XCTAssertNil(testAllTypesDesc.containingType);
+ XCTAssertNotNil(nestedMessageDesc.containingType);
+ XCTAssertEqual(nestedMessageDesc.containingType, testAllTypesDesc); // Ptr comparison
+}
+
+- (void)testDescriptor_fullName {
+ GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+ XCTAssertEqualObjects(testAllTypesDesc.fullName, @"protobuf_unittest.TestAllTypes");
+ GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+ XCTAssertEqualObjects(nestedMessageDesc.fullName, @"protobuf_unittest.TestAllTypes.NestedMessage");
+
+ // Prefixes removed.
+ GPBDescriptor *descDesc = [GPBDescriptorProto descriptor];
+ XCTAssertEqualObjects(descDesc.fullName, @"google.protobuf.DescriptorProto");
+ GPBDescriptor *descExtRngDesc = [GPBDescriptorProto_ExtensionRange descriptor];
+ XCTAssertEqualObjects(descExtRngDesc.fullName, @"google.protobuf.DescriptorProto.ExtensionRange");
+
+ // Things that get "_Class" added.
+ GPBDescriptor *pointDesc = [Point_Class descriptor];
+ XCTAssertEqualObjects(pointDesc.fullName, @"protobuf_unittest.Point");
+ GPBDescriptor *pointRectDesc = [Point_Rect descriptor];
+ XCTAssertEqualObjects(pointRectDesc.fullName, @"protobuf_unittest.Point.Rect");
+}
+
- (void)testFieldDescriptor {
GPBDescriptor *descriptor = [TestAllTypes descriptor];
diff --git a/objectivec/Tests/GPBMessageTests+Runtime.m b/objectivec/Tests/GPBMessageTests+Runtime.m
index 2cf9ccef..0058311b 100644
--- a/objectivec/Tests/GPBMessageTests+Runtime.m
+++ b/objectivec/Tests/GPBMessageTests+Runtime.m
@@ -36,6 +36,7 @@
#import "google/protobuf/MapUnittest.pbobjc.h"
#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestCycle.pbobjc.h"
#import "google/protobuf/UnittestObjcStartup.pbobjc.h"
#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
@@ -49,11 +50,24 @@
// specific.
- (void)testStartupOrdering {
- // Just have to create a message. Nothing else uses the classes from
- // this file, so the first selector invoked on the class will initialize
- // it, which also initializes the root.
+ // Message class/Root class initialization is a little tricky, so these just
+ // create some possible patterns that can be a problem. The messages don't
+ // have to be exercised, just creating them is enough to test. If there
+ // is a problem, the runtime should assert or hang.
+ //
+ // Note: the messages from these proto files should not be used in any other
+ // tests, that way when they are referenced here it will be the first use and
+ // initialization will take place now.
+
TestObjCStartupMessage *message = [TestObjCStartupMessage message];
XCTAssertNotNil(message);
+
+ CycleBaz *baz = [CycleBaz message];
+ CycleBar *bar = [CycleBar message];
+ CycleFoo *foo = [CycleFoo message];
+ XCTAssertNotNil(baz);
+ XCTAssertNotNil(bar);
+ XCTAssertNotNil(foo);
}
- (void)testProto2HasMethodSupport {
diff --git a/objectivec/Tests/GPBUnittestProtos.m b/objectivec/Tests/GPBUnittestProtos.m
index d19beee9..8d2948bf 100644
--- a/objectivec/Tests/GPBUnittestProtos.m
+++ b/objectivec/Tests/GPBUnittestProtos.m
@@ -36,6 +36,7 @@
// a descriptor as it doesn't use the classes/enums.
#import "google/protobuf/Descriptor.pbobjc.m"
+#import "google/protobuf/AnyTest.pbobjc.m"
#import "google/protobuf/MapProto2Unittest.pbobjc.m"
#import "google/protobuf/MapUnittest.pbobjc.m"
#import "google/protobuf/Unittest.pbobjc.m"
@@ -62,3 +63,11 @@
#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.m"
#import "google/protobuf/UnittestRuntimeProto2.pbobjc.m"
#import "google/protobuf/UnittestRuntimeProto3.pbobjc.m"
+
+#import "google/protobuf/UnittestExtensionChainA.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainB.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainC.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainD.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainE.pbobjc.m"
+// See GPBUnittestProtos2.m for for "UnittestExtensionChainF.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainG.pbobjc.m"
diff --git a/objectivec/Tests/GPBUnittestProtos2.m b/objectivec/Tests/GPBUnittestProtos2.m
new file mode 100644
index 00000000..ef9f0702
--- /dev/null
+++ b/objectivec/Tests/GPBUnittestProtos2.m
@@ -0,0 +1,34 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 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.
+
+// This one file in the chain tests is compiled by itself to ensure if was
+// generated with the extra #imports needed to pull in the indirect Root class
+// used in its Root registry.
+#import "google/protobuf/UnittestExtensionChainF.pbobjc.m"
diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m
index 78f4e637..041841dd 100644
--- a/objectivec/Tests/GPBWellKnownTypesTest.m
+++ b/objectivec/Tests/GPBWellKnownTypesTest.m
@@ -32,6 +32,8 @@
#import <XCTest/XCTest.h>
+#import "google/protobuf/AnyTest.pbobjc.h"
+
// A basically random interval into the future for testing with.
static const NSTimeInterval kFutureOffsetInterval = 15000;
@@ -99,4 +101,58 @@ static const NSTimeInterval kTimeAccuracy = 1e-9;
[duration2 release];
}
+- (void)testAnyHelpers {
+
+ // Set and extract covers most of the code.
+
+ TestAny *subMessage = [TestAny message];
+ subMessage.int32Value = 12345;
+ TestAny *message = [TestAny message];
+ NSError *err = nil;
+ message.anyValue = [GPBAny anyWithMessage:subMessage error:&err];
+ XCTAssertNil(err);
+
+ NSData *data = message.data;
+ XCTAssertNotNil(data);
+
+ TestAny *message2 = [TestAny parseFromData:data error:&err];
+ XCTAssertNil(err);
+ XCTAssertNotNil(message2);
+ XCTAssertTrue(message2.hasAnyValue);
+
+ TestAny *subMessage2 =
+ (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+ error:&err];
+ XCTAssertNil(err);
+ XCTAssertNotNil(subMessage2);
+ XCTAssertEqual(subMessage2.int32Value, 12345);
+
+ // NULL errorPtr in the two calls.
+
+ message.anyValue = [GPBAny anyWithMessage:subMessage error:NULL];
+ NSData *data2 = message.data;
+ XCTAssertEqualObjects(data2, data);
+
+ TestAny *subMessage3 =
+ (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+ error:NULL];
+ XCTAssertNotNil(subMessage3);
+ XCTAssertEqualObjects(subMessage2, subMessage3);
+
+ // Try to extract wrong type.
+
+ GPBTimestamp *wrongMessage =
+ (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+ error:&err];
+ XCTAssertNotNil(err);
+ XCTAssertNil(wrongMessage);
+ XCTAssertEqualObjects(err.domain, GPBWellKnownTypesErrorDomain);
+ XCTAssertEqual(err.code, GPBWellKnownTypesErrorCodeTypeURLMismatch);
+
+ wrongMessage =
+ (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+ error:NULL];
+ XCTAssertNil(wrongMessage);
+}
+
@end
diff --git a/objectivec/Tests/unittest_cycle.proto b/objectivec/Tests/unittest_cycle.proto
index 5f6f56a1..afc1b0fe 100644
--- a/objectivec/Tests/unittest_cycle.proto
+++ b/objectivec/Tests/unittest_cycle.proto
@@ -31,10 +31,8 @@ syntax = "proto2";
package protobuf_unittest;
-// Cycles in the Message graph can cause problems for the mutable classes
-// since the properties on the mutable class change types. This file just
-// needs to generate source, and that source must compile, to ensure the
-// generated source works for this sort of case.
+// Cycles in the Message graph can cause problems for message class
+// initialization order.
// You can't make a object graph that spans files, so this can only be done
// within a single proto file.
diff --git a/objectivec/Tests/unittest_extension_chain_a.proto b/objectivec/Tests/unittest_extension_chain_a.proto
new file mode 100644
index 00000000..6a227eb9
--- /dev/null
+++ b/objectivec/Tests/unittest_extension_chain_a.proto
@@ -0,0 +1,51 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest.proto";
+
+import "unittest_extension_chain_b.proto";
+import "unittest_extension_chain_c.proto";
+import "unittest_extension_chain_d.proto";
+
+// The Root for this file should end up adding the local extension and merging
+// in the extensions from D's Root (unittest and C will come via D's).
+
+message ChainAMessage {
+ optional ChainBMessage b = 1;
+ optional ChainCMessage c = 2;
+ optional ChainDMessage d = 3;
+}
+
+extend TestAllExtensions {
+ optional int32 chain_a_extension = 10001;
+}
diff --git a/objectivec/Tests/unittest_extension_chain_b.proto b/objectivec/Tests/unittest_extension_chain_b.proto
new file mode 100644
index 00000000..0da7ed3e
--- /dev/null
+++ b/objectivec/Tests/unittest_extension_chain_b.proto
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest.proto";
+
+import "unittest_extension_chain_c.proto";
+
+// The Root for this file should end up adding the local extension and merging
+// in the extensions from C's Root (unittest will come via C's).
+
+message ChainBMessage {
+ optional ChainCMessage c = 1;
+}
+
+extend TestAllExtensions {
+ optional int32 chain_b_extension = 10002;
+}
diff --git a/objectivec/Tests/unittest_extension_chain_c.proto b/objectivec/Tests/unittest_extension_chain_c.proto
new file mode 100644
index 00000000..c702900a
--- /dev/null
+++ b/objectivec/Tests/unittest_extension_chain_c.proto
@@ -0,0 +1,45 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest.proto";
+
+// The Root for this file should end up adding the local extension and merging
+// in the extensions from unittest.proto's Root.
+
+message ChainCMessage {
+ optional int32 my_field = 1;
+}
+
+extend TestAllExtensions {
+ optional int32 chain_c_extension = 10003;
+}
diff --git a/objectivec/Tests/unittest_extension_chain_d.proto b/objectivec/Tests/unittest_extension_chain_d.proto
new file mode 100644
index 00000000..f9abe3ba
--- /dev/null
+++ b/objectivec/Tests/unittest_extension_chain_d.proto
@@ -0,0 +1,49 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest.proto";
+
+import "unittest_extension_chain_b.proto";
+import "unittest_extension_chain_c.proto";
+
+// The root should end up needing to merge B (C will be merged into B, so it
+// doesn't need to be directly merged).
+
+message ChainDMessage {
+ optional ChainBMessage b = 1;
+ optional ChainCMessage c = 2;
+}
+
+extend TestAllExtensions {
+ optional int32 chain_d_extension = 10004;
+}
diff --git a/objectivec/Tests/unittest_extension_chain_e.proto b/objectivec/Tests/unittest_extension_chain_e.proto
new file mode 100644
index 00000000..fe116631
--- /dev/null
+++ b/objectivec/Tests/unittest_extension_chain_e.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest.proto";
+
+// The Root for this file should end up just merging in unittest's Root.
+
+message ChainEMessage {
+ optional TestAllTypes my_field = 1;
+}
diff --git a/objectivec/Tests/unittest_extension_chain_f.proto b/objectivec/Tests/unittest_extension_chain_f.proto
new file mode 100644
index 00000000..b9bed723
--- /dev/null
+++ b/objectivec/Tests/unittest_extension_chain_f.proto
@@ -0,0 +1,44 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "unittest_extension_chain_g.proto";
+
+// The Root for this file should just be merging in the extensions from C's
+// Root (because G doens't define anything itself).
+
+// The generated source will also have to directly import C's .h file so it can
+// compile the reference to C's Root class.
+
+message ChainFMessage {
+ optional ChainGMessage g = 1;
+}
diff --git a/objectivec/Tests/unittest_extension_chain_g.proto b/objectivec/Tests/unittest_extension_chain_g.proto
new file mode 100644
index 00000000..aee827b1
--- /dev/null
+++ b/objectivec/Tests/unittest_extension_chain_g.proto
@@ -0,0 +1,41 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "unittest_extension_chain_c.proto";
+
+// The Root for this file should just be merging in the extensions from C's
+// Root.
+
+message ChainGMessage {
+ optional ChainCMessage c = 1;
+}
diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h
index 842052fe..b88b786a 100644
--- a/objectivec/google/protobuf/Any.pbobjc.h
+++ b/objectivec/google/protobuf/Any.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m
index 25e5b4c4..e1054926 100644
--- a/objectivec/google/protobuf/Any.pbobjc.m
+++ b/objectivec/google/protobuf/Any.pbobjc.m
@@ -27,6 +27,9 @@
@implementation GPBAnyRoot
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
@end
#pragma mark - GPBAnyRoot_FileDescriptor
@@ -38,6 +41,7 @@ static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -68,7 +72,7 @@ typedef struct GPBAny__storage_ {
.number = GPBAny_FieldNumber_TypeURL,
.hasIndex = 0,
.offset = (uint32_t)offsetof(GPBAny__storage_, typeURL),
- .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldTextFormatNameCustom),
.dataType = GPBDataTypeString,
},
{
@@ -88,7 +92,7 @@ typedef struct GPBAny__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBAny__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
static const char *extraTextFormatInfo =
"\001\001\004\241!!\000";
diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h
index 182e866c..3750e093 100644
--- a/objectivec/google/protobuf/Api.pbobjc.h
+++ b/objectivec/google/protobuf/Api.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m
index cd37edaa..70437d49 100644
--- a/objectivec/google/protobuf/Api.pbobjc.m
+++ b/objectivec/google/protobuf/Api.pbobjc.m
@@ -31,18 +31,8 @@
@implementation GPBApiRoot
-+ (GPBExtensionRegistry*)extensionRegistry {
- // This is called by +initialize so there is no need to worry
- // about thread safety and initialization of registry.
- static GPBExtensionRegistry* registry = nil;
- if (!registry) {
- GPBDebugCheckRuntimeVersion();
- registry = [[GPBExtensionRegistry alloc] init];
- [registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
- [registry addExtensions:[GPBTypeRoot extensionRegistry]];
- }
- return registry;
-}
+// No extensions in the file and none of the imports (direct or indirect)
+// defined extensions, so no need to generate +extensionRegistry.
@end
@@ -55,6 +45,7 @@ static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -149,7 +140,7 @@ typedef struct GPBApi__storage_ {
.number = GPBApi_FieldNumber_Syntax,
.hasIndex = 3,
.offset = (uint32_t)offsetof(GPBApi__storage_, syntax),
- .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
.dataType = GPBDataTypeEnum,
},
};
@@ -160,7 +151,7 @@ typedef struct GPBApi__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBApi__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -223,7 +214,7 @@ typedef struct GPBMethod__storage_ {
.number = GPBMethod_FieldNumber_RequestTypeURL,
.hasIndex = 1,
.offset = (uint32_t)offsetof(GPBMethod__storage_, requestTypeURL),
- .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldTextFormatNameCustom),
.dataType = GPBDataTypeString,
},
{
@@ -241,7 +232,7 @@ typedef struct GPBMethod__storage_ {
.number = GPBMethod_FieldNumber_ResponseTypeURL,
.hasIndex = 4,
.offset = (uint32_t)offsetof(GPBMethod__storage_, responseTypeURL),
- .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldTextFormatNameCustom),
.dataType = GPBDataTypeString,
},
{
@@ -268,7 +259,7 @@ typedef struct GPBMethod__storage_ {
.number = GPBMethod_FieldNumber_Syntax,
.hasIndex = 7,
.offset = (uint32_t)offsetof(GPBMethod__storage_, syntax),
- .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
.dataType = GPBDataTypeEnum,
},
};
@@ -279,7 +270,7 @@ typedef struct GPBMethod__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBMethod__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
static const char *extraTextFormatInfo =
"\002\002\007\244\241!!\000\004\010\244\241!!\000";
@@ -350,7 +341,7 @@ typedef struct GPBMixin__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBMixin__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h
index fa91e223..090eb002 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.h
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m
index 35daa3df..f87d35db 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.m
+++ b/objectivec/google/protobuf/Duration.pbobjc.m
@@ -27,6 +27,9 @@
@implementation GPBDurationRoot
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
@end
#pragma mark - GPBDurationRoot_FileDescriptor
@@ -38,6 +41,7 @@ static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -88,7 +92,7 @@ typedef struct GPBDuration__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBDuration__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h
index 4d36174d..e0ed3e16 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.h
+++ b/objectivec/google/protobuf/Empty.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m
index 1bdd4949..9b60f36d 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.m
+++ b/objectivec/google/protobuf/Empty.pbobjc.m
@@ -27,6 +27,9 @@
@implementation GPBEmptyRoot
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
@end
#pragma mark - GPBEmptyRoot_FileDescriptor
@@ -38,6 +41,7 @@ static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -64,7 +68,7 @@ typedef struct GPBEmpty__storage_ {
fields:NULL
fieldCount:0
storageSize:sizeof(GPBEmpty__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h
index 491463f9..14ed5379 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.h
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m
index 2721fdfa..4dc8409c 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.m
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.m
@@ -27,6 +27,9 @@
@implementation GPBFieldMaskRoot
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
@end
#pragma mark - GPBFieldMaskRoot_FileDescriptor
@@ -38,6 +41,7 @@ static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -77,7 +81,7 @@ typedef struct GPBFieldMask__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBFieldMask__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h
index d9450057..417562c0 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.h
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m
index 6e3c9c07..648d736c 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.m
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.m
@@ -27,6 +27,9 @@
@implementation GPBSourceContextRoot
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
@end
#pragma mark - GPBSourceContextRoot_FileDescriptor
@@ -38,6 +41,7 @@ static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -77,7 +81,7 @@ typedef struct GPBSourceContext__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBSourceContext__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h
index a5b31cd0..163b39ba 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.h
+++ b/objectivec/google/protobuf/Struct.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m
index 8ea1f124..bc9f23ff 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.m
+++ b/objectivec/google/protobuf/Struct.pbobjc.m
@@ -28,6 +28,9 @@
@implementation GPBStructRoot
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
@end
#pragma mark - GPBStructRoot_FileDescriptor
@@ -39,6 +42,7 @@ static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -110,7 +114,7 @@ typedef struct GPBStruct__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBStruct__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -152,7 +156,7 @@ typedef struct GPBValue__storage_ {
.number = GPBValue_FieldNumber_NullValue,
.hasIndex = -1,
.offset = (uint32_t)offsetof(GPBValue__storage_, nullValue),
- .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
.dataType = GPBDataTypeEnum,
},
{
@@ -208,7 +212,7 @@ typedef struct GPBValue__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBValue__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
static const char *oneofs[] = {
"kind",
};
@@ -274,7 +278,7 @@ typedef struct GPBListValue__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBListValue__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index ebfa670f..094e9b6b 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m
index 06e3ef94..1506dff3 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.m
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.m
@@ -27,6 +27,9 @@
@implementation GPBTimestampRoot
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
@end
#pragma mark - GPBTimestampRoot_FileDescriptor
@@ -38,6 +41,7 @@ static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -88,7 +92,7 @@ typedef struct GPBTimestamp__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBTimestamp__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h
index 05411958..da923c30 100644
--- a/objectivec/google/protobuf/Type.pbobjc.h
+++ b/objectivec/google/protobuf/Type.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m
index 6c7b4efd..a36f1cd4 100644
--- a/objectivec/google/protobuf/Type.pbobjc.m
+++ b/objectivec/google/protobuf/Type.pbobjc.m
@@ -31,18 +31,8 @@
@implementation GPBTypeRoot
-+ (GPBExtensionRegistry*)extensionRegistry {
- // This is called by +initialize so there is no need to worry
- // about thread safety and initialization of registry.
- static GPBExtensionRegistry* registry = nil;
- if (!registry) {
- GPBDebugCheckRuntimeVersion();
- registry = [[GPBExtensionRegistry alloc] init];
- [registry addExtensions:[GPBAnyRoot extensionRegistry]];
- [registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
- }
- return registry;
-}
+// No extensions in the file and none of the imports (direct or indirect)
+// defined extensions, so no need to generate +extensionRegistry.
@end
@@ -55,6 +45,7 @@ static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -172,7 +163,7 @@ typedef struct GPBType__storage_ {
.number = GPBType_FieldNumber_Syntax,
.hasIndex = 2,
.offset = (uint32_t)offsetof(GPBType__storage_, syntax),
- .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
.dataType = GPBDataTypeEnum,
},
};
@@ -183,7 +174,7 @@ typedef struct GPBType__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBType__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -244,7 +235,7 @@ typedef struct GPBField__storage_ {
.number = GPBField_FieldNumber_Kind,
.hasIndex = 0,
.offset = (uint32_t)offsetof(GPBField__storage_, kind),
- .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
.dataType = GPBDataTypeEnum,
},
{
@@ -253,7 +244,7 @@ typedef struct GPBField__storage_ {
.number = GPBField_FieldNumber_Cardinality,
.hasIndex = 1,
.offset = (uint32_t)offsetof(GPBField__storage_, cardinality),
- .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
.dataType = GPBDataTypeEnum,
},
{
@@ -280,7 +271,7 @@ typedef struct GPBField__storage_ {
.number = GPBField_FieldNumber_TypeURL,
.hasIndex = 4,
.offset = (uint32_t)offsetof(GPBField__storage_, typeURL),
- .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldTextFormatNameCustom),
.dataType = GPBDataTypeString,
},
{
@@ -336,7 +327,7 @@ typedef struct GPBField__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBField__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
static const char *extraTextFormatInfo =
"\001\006\004\241!!\000";
@@ -553,7 +544,7 @@ typedef struct GPBEnum__storage_ {
.number = GPBEnum_FieldNumber_Syntax,
.hasIndex = 2,
.offset = (uint32_t)offsetof(GPBEnum__storage_, syntax),
- .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
.dataType = GPBDataTypeEnum,
},
};
@@ -564,7 +555,7 @@ typedef struct GPBEnum__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBEnum__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -641,7 +632,7 @@ typedef struct GPBEnumValue__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBEnumValue__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -695,7 +686,7 @@ typedef struct GPBOption__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBOption__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h
index e397c480..2bf6fd29 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.h
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m
index b5405a7d..c8fdeb08 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.m
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.m
@@ -27,6 +27,9 @@
@implementation GPBWrappersRoot
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
@end
#pragma mark - GPBWrappersRoot_FileDescriptor
@@ -38,6 +41,7 @@ static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
@@ -77,7 +81,7 @@ typedef struct GPBDoubleValue__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBDoubleValue__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -120,7 +124,7 @@ typedef struct GPBFloatValue__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBFloatValue__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -163,7 +167,7 @@ typedef struct GPBInt64Value__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBInt64Value__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -206,7 +210,7 @@ typedef struct GPBUInt64Value__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBUInt64Value__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -249,7 +253,7 @@ typedef struct GPBInt32Value__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBInt32Value__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -292,7 +296,7 @@ typedef struct GPBUInt32Value__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBUInt32Value__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -334,7 +338,7 @@ typedef struct GPBBoolValue__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBBoolValue__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -377,7 +381,7 @@ typedef struct GPBStringValue__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBStringValue__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
@@ -420,7 +424,7 @@ typedef struct GPBBytesValue__storage_ {
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBBytesValue__storage_)
- flags:0];
+ flags:GPBDescriptorInitializationFlag_None];
NSAssert(descriptor == nil, @"Startup recursed!");
descriptor = localDescriptor;
}
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
index 20e5d245..6f3b818a 100755
--- a/python/google/protobuf/internal/reflection_test.py
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -636,7 +636,7 @@ class ReflectionTest(unittest.TestCase):
if struct.calcsize('L') == 4:
# Python only has signed ints, so 32-bit python can't fit an uint32
# in an int.
- TestGetAndDeserialize('optional_uint32', 1 << 31, long)
+ TestGetAndDeserialize('optional_uint32', 1 << 31, integer_64)
else:
# 64-bit python can fit uint32 inside an int
TestGetAndDeserialize('optional_uint32', 1 << 31, int)
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index cfb30786..e8c2a178 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -1005,7 +1005,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/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 69f216ab..69cd5f3c 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++) {
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 6d889e63..685ed56d 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -45,16 +45,118 @@
namespace google {
namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
// 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;
+const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30002;
const char* kHeaderExtension = ".pbobjc.h";
-namespace compiler {
-namespace objectivec {
+// Checks if a message contains any extension definitions (on the message or
+// a nested message under it).
+bool MessageContainsExtensions(const Descriptor* message) {
+ if (message->extension_count() > 0) {
+ return true;
+ }
+ for (int i = 0; i < message->nested_type_count(); i++) {
+ if (MessageContainsExtensions(message->nested_type(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Checks if the file contains any extensions definitions (at the root or
+// nested under a message).
+bool FileContainsExtensions(const FileDescriptor* file) {
+ if (file->extension_count() > 0) {
+ return true;
+ }
+ for (int i = 0; i < file->message_type_count(); i++) {
+ if (MessageContainsExtensions(file->message_type(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// 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);
+ }
+}
+
+// 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 (FileContainsExtensions(file)) {
+ files->push_back(file);
+ for (int i = 0; i < file->dependency_count(); i++) {
+ const FileDescriptor* dep = file->dependency(i);
+ PruneFileAndDepsMarkingAsVisited(dep, files, files_visited);
+ }
+ } else {
+ for (int i = 0; i < file->dependency_count(); i++) {
+ const FileDescriptor* dep = file->dependency(i);
+ CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
+ files_visited);
+ }
+ }
+}
+
+// Collect the deps of the given file that contain extensions. This can be used to
+// create the chain of roots that need to be wired together.
+//
+// NOTE: If any changes are made to this and the supporting functions, you will
+// need to manually validate what the generated code is for the test files:
+// objectivec/Tests/unittest_extension_chain_*.proto
+// There are comments about what the expected code should be line and limited
+// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports
+// specifically).
+void CollectMinimalFileDepsContainingExtensions(
+ const FileDescriptor* file,
+ 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 IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) {
+ for (int i = 0; i < file->dependency_count(); i++) {
+ if (dep == file->dependency(i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
: file_(file),
@@ -204,6 +306,9 @@ 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_.generate_for_named_framework,
@@ -227,6 +332,18 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
}
}
+ // 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);
+ }
+ }
+
import_writer.Print(printer);
}
@@ -263,29 +380,11 @@ 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"
@@ -298,11 +397,20 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
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"
@@ -315,11 +423,21 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
"}\n");
}
- for (int i = 0; i < file_->dependency_count(); i++) {
- const string root_class_name(FileClassName(file_->dependency(i)));
+ 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", root_class_name);
+ "// 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();
@@ -328,27 +446,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"
@@ -356,16 +486,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"
+ " GPBDebugCheckRuntimeVersion();\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();
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index 847be983..c7fd96ac 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -210,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;
}
@@ -262,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 \?
@@ -308,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;
@@ -338,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) {
@@ -372,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) {
@@ -390,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) {
@@ -405,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) {
@@ -442,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) {
@@ -457,7 +493,7 @@ string FieldName(const FieldDescriptor* field) {
result += "_p";
}
}
- return SanitizeNameForObjC(result, "_p");
+ return SanitizeNameForObjC(result, "_p", NULL);
}
string FieldNameCapitalized(const FieldDescriptor* field) {
@@ -817,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;
}
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index b05983df..d17d44aa 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -67,6 +67,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.
@@ -83,6 +86,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
@@ -137,6 +141,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()) {
@@ -168,7 +178,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.
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/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 0028c708..92c70c0d 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -2533,7 +2533,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)
@@ -2836,7 +2836,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)
@@ -7347,7 +7347,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)
@@ -8163,7 +8163,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)
@@ -9570,7 +9570,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)
@@ -10183,7 +10183,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)
@@ -11177,7 +11177,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)
@@ -13033,7 +13033,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)
@@ -14918,7 +14918,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 94ece18e..ed5cca4b 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/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 542e5ed7..487e62b0 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 7ba909ef..a2a7f282 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -1125,7 +1125,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..fa31f763 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;
}
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) {