diff --git a/Makefile.am b/Makefile.am index cca346e9ca03..079ac7062bd7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -687,6 +687,7 @@ objectivec_EXTRA_DIST= \ objectivec/Tests/GPBDictionaryTests.m \ objectivec/Tests/GPBDictionaryTests.pddm \ objectivec/Tests/GPBExtensionRegistryTest.m \ + objectivec/Tests/GPBMessageTests+ClassNames.m \ objectivec/Tests/GPBMessageTests+Merge.m \ objectivec/Tests/GPBMessageTests+Runtime.m \ objectivec/Tests/GPBMessageTests+Serialization.m \ diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m index 41bf5adbcb67..130f1b96a83f 100644 --- a/objectivec/GPBDescriptor.m +++ b/objectivec/GPBDescriptor.m @@ -44,7 +44,7 @@ // 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 kParentClassValueKey = 0; static const char kClassNameSuffixKey = 0; // Utility function to generate selectors on the fly. @@ -126,6 +126,8 @@ @implementation GPBDescriptor { GPBFileSyntax syntax = file.syntax; BOOL fieldsIncludeDefault = (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0; + BOOL usesClassRefs = + (flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0; void *desc; for (uint32_t i = 0; i < fieldCount; ++i) { @@ -143,6 +145,7 @@ @implementation GPBDescriptor { GPBFieldDescriptor *fieldDescriptor = [[GPBFieldDescriptor alloc] initWithFieldDescription:desc includesDefault:fieldsIncludeDefault + usesClassRefs:usesClassRefs syntax:syntax]; [fields addObject:fieldDescriptor]; [fieldDescriptor release]; @@ -217,15 +220,19 @@ - (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)co extensionRangesCount_ = count; } +- (void)setupContainingMessageClass:(Class)messageClass { + objc_setAssociatedObject(self, &kParentClassValueKey, + messageClass, + OBJC_ASSOCIATION_ASSIGN); +} + - (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); + Class clazz = objc_getClass(msgClassName); + NSAssert(clazz, @"Class %s not defined", msgClassName); + [self setupContainingMessageClass:clazz]; } - (void)setupMessageClassNameSuffix:(NSString *)suffix { @@ -241,14 +248,7 @@ - (NSString *)name { } - (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); + Class parentClass = objc_getAssociatedObject(self, &kParentClassValueKey); return [parentClass descriptor]; } @@ -487,6 +487,7 @@ - (instancetype)init { - (instancetype)initWithFieldDescription:(void *)description includesDefault:(BOOL)includesDefault + usesClassRefs:(BOOL)usesClassRefs syntax:(GPBFileSyntax)syntax { if ((self = [super init])) { GPBMessageFieldDescription *coreDesc; @@ -524,12 +525,17 @@ - (instancetype)initWithFieldDescription:(void *)description // 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); + if (usesClassRefs) { + msgClass_ = coreDesc->dataTypeSpecific.clazz; + } else { + // Backwards compatibility for sources generated with older protoc. + const char *className = coreDesc->dataTypeSpecific.className; + msgClass_ = objc_getClass(className); + NSAssert(msgClass_, @"Class %s not defined", className); + } } else if (dataType == GPBDataTypeEnum) { if ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0) { enumHandling_.enumDescriptor_ = @@ -561,6 +567,15 @@ - (instancetype)initWithFieldDescription:(void *)description return self; } +- (instancetype)initWithFieldDescription:(void *)description + includesDefault:(BOOL)includesDefault + syntax:(GPBFileSyntax)syntax { + return [self initWithFieldDescription:description + includesDefault:includesDefault + usesClassRefs:NO + syntax:syntax]; +} + - (void)dealloc { if (description_->dataType == GPBDataTypeBytes && !(description_->flags & GPBFieldRepeated)) { @@ -957,33 +972,32 @@ @implementation GPBExtensionDescriptor { GPBGenericValue defaultValue_; } -@synthesize containingMessageClass = containingMessageClass_; - -- (instancetype)initWithExtensionDescription: - (GPBExtensionDescription *)description { +- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc + usesClassRefs:(BOOL)usesClassRefs { if ((self = [super init])) { - description_ = description; - -#if defined(DEBUG) && DEBUG - const char *className = description->messageOrGroupClassName; - if (className) { - NSAssert(objc_lookUpClass(className) != Nil, - @"Class %s not defined", className); - } -#endif + description_ = desc; + if (!usesClassRefs) { + // Legacy without class ref support. + const char *className = description_->messageOrGroupClass.name; + if (className) { + Class clazz = objc_lookUpClass(className); + NSAssert(clazz != Nil, @"Class %s not defined", className); + description_->messageOrGroupClass.clazz = clazz; + } - if (description->extendedClass) { - Class containingClass = objc_lookUpClass(description->extendedClass); - NSAssert(containingClass, @"Class %s not defined", - description->extendedClass); - containingMessageClass_ = containingClass; + const char *extendedClassName = description_->extendedClass.name; + if (extendedClassName) { + Class clazz = objc_lookUpClass(extendedClassName); + NSAssert(clazz, @"Class %s not defined", extendedClassName); + description_->extendedClass.clazz = clazz; + } } GPBDataType type = description_->dataType; if (type == GPBDataTypeBytes) { // Data stored as a length prefixed c-string in descriptor records. const uint8_t *bytes = - (const uint8_t *)description->defaultValue.valueData; + (const uint8_t *)description_->defaultValue.valueData; if (bytes) { uint32_t length; memcpy(&length, bytes, sizeof(length)); @@ -998,12 +1012,16 @@ - (instancetype)initWithExtensionDescription: // aren't common, we avoid the hit startup hit and it avoid initialization // order issues. } else { - defaultValue_ = description->defaultValue; + defaultValue_ = description_->defaultValue; } } return self; } +- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc { + return [self initWithExtensionDescription:desc usesClassRefs:NO]; +} + - (void)dealloc { if ((description_->dataType == GPBDataTypeBytes) && !GPBExtensionIsRepeated(description_)) { @@ -1055,7 +1073,11 @@ - (BOOL)isPackable { } - (Class)msgClass { - return objc_getClass(description_->messageOrGroupClassName); + return description_->messageOrGroupClass.clazz; +} + +- (Class)containingMessageClass { + return description_->extendedClass.clazz; } - (GPBEnumDescriptor *)enumDescriptor { diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h index 452b3f8e7ecc..09c1202a0747 100644 --- a/objectivec/GPBDescriptor_PackagePrivate.h +++ b/objectivec/GPBDescriptor_PackagePrivate.h @@ -80,7 +80,11 @@ typedef struct GPBMessageFieldDescription { // Name of ivar. const char *name; union { - const char *className; // Name for message class. + // className is deprecated and will be removed in favor of clazz. + // kept around right now for backwards compatibility. + // clazz is used iff GPBDescriptorInitializationFlag_UsesClassRefs is set. + char *className; // Name of the class of the message. + Class clazz; // Class of the message. // For enums only: If EnumDescriptors are compiled in, it will be that, // otherwise it will be the verifier. GPBEnumDescriptorFunc enumDescFunc; @@ -123,8 +127,14 @@ typedef NS_OPTIONS(uint8_t, GPBExtensionOptions) { typedef struct GPBExtensionDescription { GPBGenericValue defaultValue; const char *singletonName; - const char *extendedClass; - const char *messageOrGroupClassName; + union { + const char *name; + Class clazz; + } extendedClass; + union { + const char *name; + Class clazz; + } messageOrGroupClass; GPBEnumDescriptorFunc enumDescriptorFunc; int32_t fieldNumber; GPBDataType dataType; @@ -135,6 +145,11 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) { GPBDescriptorInitializationFlag_None = 0, GPBDescriptorInitializationFlag_FieldsWithDefault = 1 << 0, GPBDescriptorInitializationFlag_WireFormat = 1 << 1, + + // This is used as a stopgap as we move from using class names to class + // references. The runtime needs to support both until we allow a + // breaking change in the runtime. + GPBDescriptorInitializationFlag_UsesClassRefs = 1 << 2, }; @interface GPBDescriptor () { @@ -168,9 +183,12 @@ 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)setupContainingMessageClass:(Class)msgClass; - (void)setupMessageClassNameSuffix:(NSString *)suffix; +// Deprecated. Use setupContainingMessageClass instead. +- (void)setupContainingMessageClassName:(const char *)msgClassName; + @end @interface GPBFileDescriptor () @@ -206,7 +224,15 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) { // description has to be long lived, it is held as a raw pointer. - (instancetype)initWithFieldDescription:(void *)description includesDefault:(BOOL)includesDefault + usesClassRefs:(BOOL)usesClassRefs syntax:(GPBFileSyntax)syntax; + +// Deprecated. Equivalent to calling above with `usesClassRefs = NO`. +- (instancetype)initWithFieldDescription:(void *)description + includesDefault:(BOOL)includesDefault + syntax:(GPBFileSyntax)syntax; + + @end @interface GPBEnumDescriptor () @@ -246,8 +272,11 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) { @property(nonatomic, readonly) GPBWireFormat alternateWireType; // description has to be long lived, it is held as a raw pointer. -- (instancetype)initWithExtensionDescription: - (GPBExtensionDescription *)description; +- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc + usesClassRefs:(BOOL)usesClassRefs; +// Deprecated. Calls above with `usesClassRefs = NO` +- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc; + - (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other; @end diff --git a/objectivec/GPBRuntimeTypes.h b/objectivec/GPBRuntimeTypes.h index 81480548fea5..b269f1de1123 100644 --- a/objectivec/GPBRuntimeTypes.h +++ b/objectivec/GPBRuntimeTypes.h @@ -142,3 +142,10 @@ typedef struct GPBExtensionRange { /** Exclusive. */ uint32_t end; } GPBExtensionRange; + +/** + A type to represent a reference to an Objective C class. + This is actually an `objc_class` but the runtime headers will not allow us to + reference `objc_class`. +*/ +typedef struct GPBObjcClassReference GPBObjcClassReference; diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj index 9b0af314fd0e..6bc4d322e348 100644 --- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; }; 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */; }; 8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 8BFF9D1A23AD582300E63E32 /* GPBMessageTests+ClassNames.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BFF9D1923AD582200E63E32 /* GPBMessageTests+ClassNames.m */; }; F401DC2D1A8D444600FCC765 /* GPBArray.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC2B1A8D444600FCC765 /* GPBArray.m */; }; F401DC331A8E5C0200FCC765 /* GPBArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC321A8E5C0200FCC765 /* GPBArrayTests.m */; }; F40EE4AB206BF8B90071091A /* GPBCompileTest01.m in Sources */ = {isa = PBXBuildFile; fileRef = F40EE488206BF8B00071091A /* GPBCompileTest01.m */; }; @@ -181,6 +182,7 @@ 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = ""; }; 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = ""; }; 8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRuntimeTypes.h; sourceTree = ""; }; + 8BFF9D1923AD582200E63E32 /* GPBMessageTests+ClassNames.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+ClassNames.m"; sourceTree = ""; }; F401DC2A1A8D444600FCC765 /* GPBArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBArray.h; sourceTree = ""; }; F401DC2B1A8D444600FCC765 /* GPBArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArray.m; sourceTree = ""; }; F401DC321A8E5C0200FCC765 /* GPBArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArrayTests.m; sourceTree = ""; }; @@ -485,6 +487,7 @@ 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */, F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */, F4487C741AADF7F500531423 /* GPBMessageTests+Runtime.m */, + 8BFF9D1923AD582200E63E32 /* GPBMessageTests+ClassNames.m */, F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */, F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */, F41C175C1833D3310064ED4D /* GPBPerfTests.m */, @@ -656,6 +659,7 @@ developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( + English, en, ); mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; @@ -770,6 +774,7 @@ 8B4248BB1A8C256A00BC1EC6 /* GPBSwiftTests.swift in Sources */, F40EE50C206C06640071091A /* GPBCompileTest25.m in Sources */, F4584D821ECCB52A00803AB6 /* GPBExtensionRegistryTest.m in Sources */, + 8BFF9D1A23AD582300E63E32 /* GPBMessageTests+ClassNames.m in Sources */, 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */, F4487C751AADF7F500531423 /* GPBMessageTests+Runtime.m in Sources */, F40EE4AC206BF8B90071091A /* GPBCompileTest02.m in Sources */, diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj index 9f1d825c6fd6..1b60be25a423 100644 --- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; }; 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */; }; 8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 8BFF9D1C23AD593C00E63E32 /* GPBMessageTests+ClassNames.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BFF9D1B23AD593B00E63E32 /* GPBMessageTests+ClassNames.m */; }; F401DC351A8E5C6F00FCC765 /* GPBArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */; }; F40EE4F0206BF91E0071091A /* GPBCompileTest01.m in Sources */ = {isa = PBXBuildFile; fileRef = F40EE4CD206BF9170071091A /* GPBCompileTest01.m */; }; F40EE4F1206BF91E0071091A /* GPBCompileTest02.m in Sources */ = {isa = PBXBuildFile; fileRef = F40EE4C6206BF9170071091A /* GPBCompileTest02.m */; }; @@ -183,6 +184,7 @@ 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = ""; }; 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = ""; }; 8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRuntimeTypes.h; sourceTree = ""; }; + 8BFF9D1B23AD593B00E63E32 /* GPBMessageTests+ClassNames.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+ClassNames.m"; sourceTree = ""; }; F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArrayTests.m; sourceTree = ""; }; F40EE4C2206BF9160071091A /* GPBCompileTest08.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCompileTest08.m; sourceTree = ""; }; F40EE4C3206BF9160071091A /* GPBCompileTest04.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCompileTest04.m; sourceTree = ""; }; @@ -491,6 +493,7 @@ 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */, F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */, F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */, + 8BFF9D1B23AD593B00E63E32 /* GPBMessageTests+ClassNames.m */, F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */, F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */, F41C175C1833D3310064ED4D /* GPBPerfTests.m */, @@ -663,6 +666,7 @@ developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( + English, en, ); mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; @@ -777,6 +781,7 @@ 8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */, F40EE512206C068D0071091A /* GPBCompileTest25.m in Sources */, F4584D831ECCB53600803AB6 /* GPBExtensionRegistryTest.m in Sources */, + 8BFF9D1C23AD593C00E63E32 /* GPBMessageTests+ClassNames.m in Sources */, 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */, F4487C771AADF84900531423 /* GPBMessageTests+Runtime.m in Sources */, F40EE4F1206BF91E0071091A /* GPBCompileTest02.m in Sources */, @@ -851,6 +856,7 @@ buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_WEAK = YES; + ENABLE_BITCODE = YES; FRAMEWORK_SEARCH_PATHS = ( "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", "$(inherited)", @@ -883,6 +889,7 @@ buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_WEAK = YES; + ENABLE_BITCODE = YES; FRAMEWORK_SEARCH_PATHS = ( "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", "$(inherited)", diff --git a/objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj index c40c2aaa15a7..3962083c18fd 100644 --- a/objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; }; 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */; }; 8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 8BFF9D1E23AD599400E63E32 /* GPBMessageTests+ClassNames.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BFF9D1D23AD599400E63E32 /* GPBMessageTests+ClassNames.m */; }; F401DC351A8E5C6F00FCC765 /* GPBArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */; }; F40EE4F0206BF91E0071091A /* GPBCompileTest01.m in Sources */ = {isa = PBXBuildFile; fileRef = F40EE4CD206BF9170071091A /* GPBCompileTest01.m */; }; F40EE4F1206BF91E0071091A /* GPBCompileTest02.m in Sources */ = {isa = PBXBuildFile; fileRef = F40EE4C6206BF9170071091A /* GPBCompileTest02.m */; }; @@ -183,6 +184,7 @@ 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = ""; }; 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = ""; }; 8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRuntimeTypes.h; sourceTree = ""; }; + 8BFF9D1D23AD599400E63E32 /* GPBMessageTests+ClassNames.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+ClassNames.m"; sourceTree = ""; }; F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArrayTests.m; sourceTree = ""; }; F40EE4C2206BF9160071091A /* GPBCompileTest08.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCompileTest08.m; sourceTree = ""; }; F40EE4C3206BF9160071091A /* GPBCompileTest04.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCompileTest04.m; sourceTree = ""; }; @@ -491,6 +493,7 @@ 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */, F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */, F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */, + 8BFF9D1D23AD599400E63E32 /* GPBMessageTests+ClassNames.m */, F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */, F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */, F41C175C1833D3310064ED4D /* GPBPerfTests.m */, @@ -663,6 +666,7 @@ developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( + English, en, ); mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; @@ -777,6 +781,7 @@ 8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */, F40EE512206C068D0071091A /* GPBCompileTest25.m in Sources */, F4584D831ECCB53600803AB6 /* GPBExtensionRegistryTest.m in Sources */, + 8BFF9D1E23AD599400E63E32 /* GPBMessageTests+ClassNames.m in Sources */, 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */, F4487C771AADF84900531423 /* GPBMessageTests+Runtime.m in Sources */, F40EE4F1206BF91E0071091A /* GPBCompileTest02.m in Sources */, diff --git a/objectivec/Tests/GPBMessageTests+ClassNames.m b/objectivec/Tests/GPBMessageTests+ClassNames.m new file mode 100644 index 000000000000..31d15b534a76 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests+ClassNames.m @@ -0,0 +1,164 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "GPBTestUtilities.h" + +#import + +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBExtensionRegistry.h" +#import "GPBMessage.h" +#import "GPBRootObject_PackagePrivate.h" + +// Support classes for tests using old class name (vs classrefs) interfaces. +@interface MessageLackingClazzRoot : GPBRootObject +@end + +@interface MessageLackingClazzRoot (DynamicMethods) ++ (GPBExtensionDescriptor *)ext1; +@end + +@interface MessageLackingClazz : GPBMessage +@property(copy, nonatomic) NSString *foo; +@end + +@implementation MessageLackingClazz + +@dynamic foo; + +typedef struct MessageLackingClazz_storage_ { + uint32_t _has_storage_[1]; + NSString *foo; +} MessageLackingClazz_storage_; + ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "foo", + .dataTypeSpecific.className = "NSString", + .number = 1, + .hasIndex = 0, + .offset = (uint32_t)offsetof(MessageLackingClazz_storage_, foo), + .flags = (GPBFieldFlags)(GPBFieldOptional), + .dataType = GPBDataTypeMessage, + }, + }; + GPBFileDescriptor *desc = + [[[GPBFileDescriptor alloc] initWithPackage:@"test" + objcPrefix:@"TEST" + syntax:GPBFileSyntaxProto3] autorelease]; + + // GPBDescriptorInitializationFlag_UsesClassRefs intentionally not set here + descriptor = + [GPBDescriptor allocDescriptorForClass:[MessageLackingClazz class] + rootClass:[MessageLackingClazzRoot class] + file:desc + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(MessageLackingClazz_storage_) + flags:GPBDescriptorInitializationFlag_None]; + [descriptor setupContainingMessageClassName:"MessageLackingClazz"]; + } + return descriptor; +} +@end + +@implementation MessageLackingClazzRoot + ++ (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) { + registry = [[GPBExtensionRegistry alloc] init]; + static GPBExtensionDescription descriptions[] = { + { + .defaultValue.valueMessage = NULL, + .singletonName = "MessageLackingClazzRoot_ext1", + .extendedClass.name = "MessageLackingClazz", + .messageOrGroupClass.name = "MessageLackingClazz", + .enumDescriptorFunc = NULL, + .fieldNumber = 1, + .dataType = GPBDataTypeMessage, + // GPBExtensionUsesClazz Intentionally not set + .options = 0, + }, + }; + for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) { + // Intentionall using `-initWithExtensionDescription:` and not ` + // -initWithExtensionDescription:usesClassRefs:` to test backwards + // compatibility + GPBExtensionDescriptor *extension = + [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]]; + [registry addExtension:extension]; + [self globallyRegisterExtension:extension]; + [extension release]; + } + // None of the imports (direct or indirect) defined extensions, so no need to add + // them to this registry. + } + return registry; +} +@end + +@interface MessageClassNameTests : GPBTestCase +@end + +@implementation MessageClassNameTests + +- (void)testClassNameSupported { + // This tests backwards compatibility to make sure we support older sources + // that use class names instead of references. + GPBDescriptor *desc = [MessageLackingClazz descriptor]; + GPBFieldDescriptor *fieldDesc = [desc fieldWithName:@"foo"]; + XCTAssertEqualObjects(fieldDesc.msgClass, [NSString class]); +} + +- (void)testSetupContainingMessageClassNameSupported { + // This tests backwards compatibility to make sure we support older sources + // that use class names instead of references. + GPBDescriptor *desc = [MessageLackingClazz descriptor]; + GPBDescriptor *container = [desc containingType]; + XCTAssertEqualObjects(container.messageClass, [MessageLackingClazz class]); +} + +- (void)testExtensionsNameSupported { + // This tests backwards compatibility to make sure we support older sources + // that use class names instead of references. + GPBExtensionDescriptor *desc = [MessageLackingClazzRoot ext1]; + Class containerClass = [desc containingMessageClass]; + XCTAssertEqualObjects(containerClass, [MessageLackingClazz class]); + Class msgClass = [desc msgClass]; + XCTAssertEqualObjects(msgClass, [MessageLackingClazz class]); +} + +@end diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m index f1e815fd120f..d396e8422a46 100644 --- a/objectivec/google/protobuf/Any.pbobjc.m +++ b/objectivec/google/protobuf/Any.pbobjc.m @@ -68,7 +68,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "typeURL", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBAny_FieldNumber_TypeURL, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBAny__storage_, typeURL), @@ -77,7 +77,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBAny_FieldNumber_Value, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBAny__storage_, value), @@ -92,7 +92,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBAny__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS static const char *extraTextFormatInfo = "\001\001\004\241!!\000"; diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m index 410239996174..1463f0dc9de4 100644 --- a/objectivec/google/protobuf/Api.pbobjc.m +++ b/objectivec/google/protobuf/Api.pbobjc.m @@ -26,6 +26,18 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#pragma mark - Objective C Class references +// This somewhat arcane code forces linkage of classes from static archives by +// adding a concrete reference to the classes. +// We don't use `[Foo class]` because we need a static value for our initializer. +// This also has the added benefit of reducing size in that we don't have to +// encode the class names and look them up at runtime. +extern const GPBObjcClassReference OBJC_CLASS_$_GPBMethod; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBMixin; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBOption; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBSourceContext; #pragma mark - GPBApiRoot @@ -82,7 +94,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "name", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBApi_FieldNumber_Name, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBApi__storage_, name), @@ -91,7 +103,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "methodsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBMethod), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBMethod), .number = GPBApi_FieldNumber_MethodsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBApi__storage_, methodsArray), @@ -100,7 +112,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBOption), .number = GPBApi_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBApi__storage_, optionsArray), @@ -109,7 +121,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "version", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBApi_FieldNumber_Version, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBApi__storage_, version), @@ -118,7 +130,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "sourceContext", - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBSourceContext), .number = GPBApi_FieldNumber_SourceContext, .hasIndex = 2, .offset = (uint32_t)offsetof(GPBApi__storage_, sourceContext), @@ -127,7 +139,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "mixinsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBMixin), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBMixin), .number = GPBApi_FieldNumber_MixinsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBApi__storage_, mixinsArray), @@ -151,7 +163,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBApi__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -203,7 +215,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "name", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBMethod_FieldNumber_Name, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBMethod__storage_, name), @@ -212,7 +224,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "requestTypeURL", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBMethod_FieldNumber_RequestTypeURL, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBMethod__storage_, requestTypeURL), @@ -221,7 +233,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "requestStreaming", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBMethod_FieldNumber_RequestStreaming, .hasIndex = 2, .offset = 3, // Stored in _has_storage_ to save space. @@ -230,7 +242,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "responseTypeURL", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBMethod_FieldNumber_ResponseTypeURL, .hasIndex = 4, .offset = (uint32_t)offsetof(GPBMethod__storage_, responseTypeURL), @@ -239,7 +251,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "responseStreaming", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBMethod_FieldNumber_ResponseStreaming, .hasIndex = 5, .offset = 6, // Stored in _has_storage_ to save space. @@ -248,7 +260,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBOption), .number = GPBMethod_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBMethod__storage_, optionsArray), @@ -272,7 +284,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBMethod__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS static const char *extraTextFormatInfo = "\002\002\007\244\241!!\000\004\010\244\241!!\000"; @@ -321,7 +333,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "name", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBMixin_FieldNumber_Name, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBMixin__storage_, name), @@ -330,7 +342,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "root", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBMixin_FieldNumber_Root, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBMixin__storage_, root), @@ -345,7 +357,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBMixin__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m index 1b718a12e7a6..5d1134bdad08 100644 --- a/objectivec/google/protobuf/Duration.pbobjc.m +++ b/objectivec/google/protobuf/Duration.pbobjc.m @@ -68,7 +68,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "seconds", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBDuration_FieldNumber_Seconds, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBDuration__storage_, seconds), @@ -77,7 +77,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "nanos", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBDuration_FieldNumber_Nanos, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBDuration__storage_, nanos), @@ -92,7 +92,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBDuration__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m index 4cb0f12c353d..9738b0a6b356 100644 --- a/objectivec/google/protobuf/Empty.pbobjc.m +++ b/objectivec/google/protobuf/Empty.pbobjc.m @@ -68,7 +68,7 @@ + (GPBDescriptor *)descriptor { fields:NULL fieldCount:0 storageSize:sizeof(GPBEmpty__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m index 2e6b2eef7c75..4d72efbd2c32 100644 --- a/objectivec/google/protobuf/FieldMask.pbobjc.m +++ b/objectivec/google/protobuf/FieldMask.pbobjc.m @@ -66,7 +66,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "pathsArray", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBFieldMask_FieldNumber_PathsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBFieldMask__storage_, pathsArray), @@ -81,7 +81,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBFieldMask__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m index c955f2b4fae6..d425cc85b3be 100644 --- a/objectivec/google/protobuf/SourceContext.pbobjc.m +++ b/objectivec/google/protobuf/SourceContext.pbobjc.m @@ -66,7 +66,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "fileName", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBSourceContext_FieldNumber_FileName, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBSourceContext__storage_, fileName), @@ -81,7 +81,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBSourceContext__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m index 3873f5a0338c..e8e181b25431 100644 --- a/objectivec/google/protobuf/Struct.pbobjc.m +++ b/objectivec/google/protobuf/Struct.pbobjc.m @@ -25,6 +25,17 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdirect-ivar-access" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#pragma mark - Objective C Class references +// This somewhat arcane code forces linkage of classes from static archives by +// adding a concrete reference to the classes. +// We don't use `[Foo class]` because we need a static value for our initializer. +// This also has the added benefit of reducing size in that we don't have to +// encode the class names and look them up at runtime. +extern const GPBObjcClassReference OBJC_CLASS_$_GPBListValue; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBStruct; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBValue; #pragma mark - GPBStructRoot @@ -102,7 +113,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "fields", - .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBValue), .number = GPBStruct_FieldNumber_Fields, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBStruct__storage_, fields), @@ -117,7 +128,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBStruct__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -166,7 +177,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "numberValue", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBValue_FieldNumber_NumberValue, .hasIndex = -1, .offset = (uint32_t)offsetof(GPBValue__storage_, numberValue), @@ -175,7 +186,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "stringValue", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBValue_FieldNumber_StringValue, .hasIndex = -1, .offset = (uint32_t)offsetof(GPBValue__storage_, stringValue), @@ -184,7 +195,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "boolValue", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBValue_FieldNumber_BoolValue, .hasIndex = -1, .offset = 0, // Stored in _has_storage_ to save space. @@ -193,7 +204,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "structValue", - .dataTypeSpecific.className = GPBStringifySymbol(GPBStruct), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBStruct), .number = GPBValue_FieldNumber_StructValue, .hasIndex = -1, .offset = (uint32_t)offsetof(GPBValue__storage_, structValue), @@ -202,7 +213,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "listValue", - .dataTypeSpecific.className = GPBStringifySymbol(GPBListValue), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBListValue), .number = GPBValue_FieldNumber_ListValue, .hasIndex = -1, .offset = (uint32_t)offsetof(GPBValue__storage_, listValue), @@ -217,7 +228,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; static const char *oneofs[] = { "kind", }; @@ -270,7 +281,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "valuesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBValue), .number = GPBListValue_FieldNumber_ValuesArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBListValue__storage_, valuesArray), @@ -285,7 +296,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBListValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m index 05eb3a5d295d..6368885df018 100644 --- a/objectivec/google/protobuf/Timestamp.pbobjc.m +++ b/objectivec/google/protobuf/Timestamp.pbobjc.m @@ -68,7 +68,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "seconds", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBTimestamp_FieldNumber_Seconds, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBTimestamp__storage_, seconds), @@ -77,7 +77,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "nanos", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBTimestamp_FieldNumber_Nanos, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBTimestamp__storage_, nanos), @@ -92,7 +92,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBTimestamp__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m index 7451edc6e21d..0c48e6b31219 100644 --- a/objectivec/google/protobuf/Type.pbobjc.m +++ b/objectivec/google/protobuf/Type.pbobjc.m @@ -28,6 +28,19 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#pragma mark - Objective C Class references +// This somewhat arcane code forces linkage of classes from static archives by +// adding a concrete reference to the classes. +// We don't use `[Foo class]` because we need a static value for our initializer. +// This also has the added benefit of reducing size in that we don't have to +// encode the class names and look them up at runtime. +extern const GPBObjcClassReference OBJC_CLASS_$_GPBAny; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBEnumValue; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBField; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBOption; +extern const GPBObjcClassReference OBJC_CLASS_$_GPBSourceContext; #pragma mark - GPBTypeRoot @@ -117,7 +130,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "name", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBType_FieldNumber_Name, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBType__storage_, name), @@ -126,7 +139,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "fieldsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBField), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBField), .number = GPBType_FieldNumber_FieldsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBType__storage_, fieldsArray), @@ -135,7 +148,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "oneofsArray", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBType_FieldNumber_OneofsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBType__storage_, oneofsArray), @@ -144,7 +157,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBOption), .number = GPBType_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBType__storage_, optionsArray), @@ -153,7 +166,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "sourceContext", - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBSourceContext), .number = GPBType_FieldNumber_SourceContext, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBType__storage_, sourceContext), @@ -177,7 +190,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBType__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -254,7 +267,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "number", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBField_FieldNumber_Number, .hasIndex = 2, .offset = (uint32_t)offsetof(GPBField__storage_, number), @@ -263,7 +276,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "name", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBField_FieldNumber_Name, .hasIndex = 3, .offset = (uint32_t)offsetof(GPBField__storage_, name), @@ -272,7 +285,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "typeURL", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBField_FieldNumber_TypeURL, .hasIndex = 4, .offset = (uint32_t)offsetof(GPBField__storage_, typeURL), @@ -281,7 +294,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "oneofIndex", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBField_FieldNumber_OneofIndex, .hasIndex = 5, .offset = (uint32_t)offsetof(GPBField__storage_, oneofIndex), @@ -290,7 +303,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "packed", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBField_FieldNumber_Packed, .hasIndex = 6, .offset = 7, // Stored in _has_storage_ to save space. @@ -299,7 +312,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBOption), .number = GPBField_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBField__storage_, optionsArray), @@ -308,7 +321,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "jsonName", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBField_FieldNumber_JsonName, .hasIndex = 8, .offset = (uint32_t)offsetof(GPBField__storage_, jsonName), @@ -317,7 +330,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "defaultValue", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBField_FieldNumber_DefaultValue, .hasIndex = 9, .offset = (uint32_t)offsetof(GPBField__storage_, defaultValue), @@ -332,7 +345,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBField__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS static const char *extraTextFormatInfo = "\001\006\004\241!!\000"; @@ -513,7 +526,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "name", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBEnum_FieldNumber_Name, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBEnum__storage_, name), @@ -522,7 +535,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "enumvalueArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValue), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBEnumValue), .number = GPBEnum_FieldNumber_EnumvalueArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBEnum__storage_, enumvalueArray), @@ -531,7 +544,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBOption), .number = GPBEnum_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBEnum__storage_, optionsArray), @@ -540,7 +553,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "sourceContext", - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBSourceContext), .number = GPBEnum_FieldNumber_SourceContext, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBEnum__storage_, sourceContext), @@ -564,7 +577,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBEnum__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -610,7 +623,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "name", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBEnumValue_FieldNumber_Name, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBEnumValue__storage_, name), @@ -619,7 +632,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "number", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBEnumValue_FieldNumber_Number, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBEnumValue__storage_, number), @@ -628,7 +641,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBOption), .number = GPBEnumValue_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(GPBEnumValue__storage_, optionsArray), @@ -643,7 +656,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBEnumValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -675,7 +688,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "name", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBOption_FieldNumber_Name, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBOption__storage_, name), @@ -684,7 +697,7 @@ + (GPBDescriptor *)descriptor { }, { .name = "value", - .dataTypeSpecific.className = GPBStringifySymbol(GPBAny), + .dataTypeSpecific.clazz = ((__bridge Class)&OBJC_CLASS_$_GPBAny), .number = GPBOption_FieldNumber_Value, .hasIndex = 1, .offset = (uint32_t)offsetof(GPBOption__storage_, value), @@ -699,7 +712,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBOption__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m index f91d345041ea..19bca6f5c468 100644 --- a/objectivec/google/protobuf/Wrappers.pbobjc.m +++ b/objectivec/google/protobuf/Wrappers.pbobjc.m @@ -66,7 +66,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBDoubleValue_FieldNumber_Value, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBDoubleValue__storage_, value), @@ -81,7 +81,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBDoubleValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -111,7 +111,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBFloatValue_FieldNumber_Value, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBFloatValue__storage_, value), @@ -126,7 +126,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBFloatValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -156,7 +156,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBInt64Value_FieldNumber_Value, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBInt64Value__storage_, value), @@ -171,7 +171,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBInt64Value__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -201,7 +201,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBUInt64Value_FieldNumber_Value, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBUInt64Value__storage_, value), @@ -216,7 +216,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBUInt64Value__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -246,7 +246,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBInt32Value_FieldNumber_Value, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBInt32Value__storage_, value), @@ -261,7 +261,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBInt32Value__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -291,7 +291,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBUInt32Value_FieldNumber_Value, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBUInt32Value__storage_, value), @@ -306,7 +306,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBUInt32Value__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -335,7 +335,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBBoolValue_FieldNumber_Value, .hasIndex = 0, .offset = 1, // Stored in _has_storage_ to save space. @@ -350,7 +350,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBBoolValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -380,7 +380,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBStringValue_FieldNumber_Value, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBStringValue__storage_, value), @@ -395,7 +395,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBStringValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG @@ -425,7 +425,7 @@ + (GPBDescriptor *)descriptor { static GPBMessageFieldDescription fields[] = { { .name = "value", - .dataTypeSpecific.className = NULL, + .dataTypeSpecific.clazz = Nil, .number = GPBBytesValue_FieldNumber_Value, .hasIndex = 0, .offset = (uint32_t)offsetof(GPBBytesValue__storage_, value), @@ -440,7 +440,7 @@ + (GPBDescriptor *)descriptor { fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBBytesValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; + flags:GPBDescriptorInitializationFlag_UsesClassRefs]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc index bf65de3be268..a67d1a2ebab9 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc @@ -84,24 +84,24 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization( io::Printer* printer) { std::map vars; vars["root_class_and_method_name"] = root_class_and_method_name_; - vars["extended_type"] = ClassName(descriptor_->containing_type()); + const string containing_type = ClassName(descriptor_->containing_type()); + vars["extended_type"] = ObjCClassSymbolReference(containing_type); vars["number"] = StrCat(descriptor_->number()); std::vector options; if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated"); if (descriptor_->is_packed()) options.push_back("GPBExtensionPacked"); - if (descriptor_->containing_type()->options().message_set_wire_format()) + if (descriptor_->containing_type()->options().message_set_wire_format()) { options.push_back("GPBExtensionSetWireFormat"); - + } vars["options"] = BuildFlagsString(FLAGTYPE_EXTENSION, options); ObjectiveCType objc_type = GetObjectiveCType(descriptor_); - string singular_type; if (objc_type == OBJECTIVECTYPE_MESSAGE) { - vars["type"] = string("GPBStringifySymbol(") + - ClassName(descriptor_->message_type()) + ")"; + std::string message_type = ClassName(descriptor_->message_type()); + vars["type"] = ObjCClassSymbolReference(message_type); } else { - vars["type"] = "NULL"; + vars["type"] = "Nil"; } vars["default_name"] = GPBGenericValueFieldName(descriptor_); @@ -124,8 +124,8 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization( "{\n" " .defaultValue.$default_name$ = $default$,\n" " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" - " .extendedClass = GPBStringifySymbol($extended_type$),\n" - " .messageOrGroupClassName = $type$,\n" + " .extendedClass.clazz = $extended_type$,\n" + " .messageOrGroupClass.clazz = $type$,\n" " .enumDescriptorFunc = $enum_desc_func_name$,\n" " .fieldNumber = $number$,\n" " .dataType = $extension_type$,\n" @@ -133,11 +133,23 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization( "},\n"); } +void ExtensionGenerator::DetermineObjectiveCClassDefinitions( + std::set* fwd_decls) { + string extended_type = ClassName(descriptor_->containing_type()); + fwd_decls->insert(ObjCClassSymbolDefinition(extended_type)); + ObjectiveCType objc_type = GetObjectiveCType(descriptor_); + if (objc_type == OBJECTIVECTYPE_MESSAGE) { + string message_type = ClassName(descriptor_->message_type()); + fwd_decls->insert(ObjCClassSymbolDefinition(message_type)); + } +} + void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) { printer->Print( "[registry addExtension:$root_class_and_method_name$];\n", "root_class_and_method_name", root_class_and_method_name_); } + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.h b/src/google/protobuf/compiler/objectivec/objectivec_extension.h index d49a4f1cc2a6..1bc19d818770 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_extension.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.h @@ -51,6 +51,7 @@ class ExtensionGenerator { void GenerateMembersHeader(io::Printer* printer); void GenerateStaticVariablesInitialization(io::Printer* printer); void GenerateRegistrationSource(io::Printer* printer); + void DetermineObjectiveCClassDefinitions(std::set* fwd_decls); private: string method_name_; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc index 19be007bfb89..829f4258f980 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -97,8 +97,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["default"] = DefaultValue(descriptor); (*variables)["default_name"] = GPBGenericValueFieldName(descriptor); - (*variables)["dataTypeSpecific_name"] = "className"; - (*variables)["dataTypeSpecific_value"] = "NULL"; + (*variables)["dataTypeSpecific_name"] = "clazz"; + (*variables)["dataTypeSpecific_value"] = "Nil"; (*variables)["storage_offset_value"] = "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")"; @@ -181,6 +181,11 @@ void FieldGenerator::DetermineForwardDeclarations( // Nothing } +void FieldGenerator::DetermineObjectiveCClassDefinitions( + std::set* fwd_decls) const { + // Nothing +} + void FieldGenerator::GenerateFieldDescription( io::Printer* printer, bool include_default) const { // Printed in the same order as the structure decl. diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h index 24465d0a36f0..68c470a50b43 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h @@ -66,6 +66,7 @@ class FieldGenerator { // Exposed for subclasses, should always call it on the parent class also. virtual void DetermineForwardDeclarations(std::set* fwd_decls) const; + virtual void DetermineObjectiveCClassDefinitions(std::set* fwd_decls) const; // Used during generation, not intended to be extended by subclasses. void GenerateFieldDescription( diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index 7bc585e9bafe..369b3be6a2df 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -398,10 +398,20 @@ void FileGenerator::GenerateSource(io::Printer *printer) { } } + std::set fwd_decls; + for (const auto& generator : message_generators_) { + generator->DetermineObjectiveCClassDefinitions(&fwd_decls); + } + for (const auto& generator : extension_generators_) { + generator->DetermineObjectiveCClassDefinitions(&fwd_decls); + } + // Note: // deprecated-declarations suppression is only needed if some place in this // proto file is something deprecated or if it references something from // another file that is deprecated. + // dollar-in-identifier-extension is needed because we use references to + // objc class names that have $ in identifiers. printer->Print( "// @@protoc_insertion_point(imports)\n" "\n" @@ -414,9 +424,28 @@ void FileGenerator::GenerateSource(io::Printer *printer) { printer->Print( "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n"); } - + if (fwd_decls.size() > 0) { + printer->Print( + "#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n"); + } + printer->Print( + "\n"); + if (fwd_decls.size() > 0) { + printer->Print( + "#pragma mark - Objective C Class references\n" + "// This somewhat arcane code forces linkage of classes from static archives by\n" + "// adding a concrete reference to the classes.\n" + "// We don't use `[Foo class]` because we need a static value for our initializer.\n" + "// This also has the added benefit of reducing size in that we don't have to\n" + "// encode the class names and look them up at runtime.\n"); + } + for (const auto& i : fwd_decls) { + printer->Print("$value$\n", "value", i); + } + if (fwd_decls.size() > 0) { + printer->Print("\n"); + } printer->Print( - "\n" "#pragma mark - $root_class_name$\n" "\n" "@implementation $root_class_name$\n\n", @@ -454,7 +483,8 @@ void FileGenerator::GenerateSource(io::Printer *printer) { "};\n" "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n" " GPBExtensionDescriptor *extension =\n" - " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]];\n" + " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]\n" + " usesClassRefs:YES];\n" " [registry addExtension:extension];\n" " [self globallyRegisterExtension:extension];\n" " [extension release];\n" diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index 09a808bf405c..97bc75be9659 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -585,6 +585,19 @@ string OneofNameCapitalized(const OneofDescriptor* descriptor) { return result; } +static string ObjCClassSymbolName(const string& class_name) { + return string("OBJC_CLASS_$_") + class_name; +} + +string ObjCClassSymbolReference(const string& class_name) { + return "((__bridge Class)&" + ObjCClassSymbolName(class_name) + ")"; +} + +string ObjCClassSymbolDefinition(const string& class_name) { + const string &ref = ObjCClassSymbolName(class_name); + return "extern const GPBObjcClassReference " + ref + ";"; +} + string UnCamelCaseFieldName(const string& name, const FieldDescriptor* field) { string worker(name); if (HasSuffixString(worker, "_p")) { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index 98ec7db8fbc6..5334addc51d1 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -118,6 +118,15 @@ string PROTOC_EXPORT OneofEnumName(const OneofDescriptor* descriptor); string PROTOC_EXPORT OneofName(const OneofDescriptor* descriptor); string PROTOC_EXPORT OneofNameCapitalized(const OneofDescriptor* descriptor); +// Returns a symbol that can be used in C code to refer to an Objective C +// class without initializing the class. +string PROTOC_EXPORT ObjCClassSymbolReference(const string& className); + +// Defines a symbol that can be used in C code to refer to an Objective C +// class without initializing the class. Use a corresponding +// ObjCClassSymbolReference to reference it. +string PROTOC_EXPORT ObjCClassSymbolDefinition(const string& className); + inline bool HasFieldPresence(const FileDescriptor* file) { return file->syntax() != FileDescriptor::SYNTAX_PROTO3; } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc index 6abad8bd0061..55e5bf9da649 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -112,6 +112,7 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, if (value_field_flags.find("GPBFieldHasEnumDescriptor") != string::npos) { field_flags.push_back("GPBFieldHasEnumDescriptor"); } + variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags); ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); @@ -170,6 +171,17 @@ void MapFieldGenerator::DetermineForwardDeclarations( } } +void MapFieldGenerator::DetermineObjectiveCClassDefinitions( + std::set* fwd_decls) const { + // Class name is already in "storage_type". + const FieldDescriptor* value_descriptor = + descriptor_->message_type()->FindFieldByName("value"); + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) { + fwd_decls->insert(ObjCClassSymbolDefinition( + value_field_generator_->variable("storage_type"))); + } +} + } // namespace objectivec } // namespace compiler diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h index c3085019ee3b..da18d579f556 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h @@ -54,6 +54,7 @@ class MapFieldGenerator : public RepeatedFieldGenerator { MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); virtual ~MapFieldGenerator(); + virtual void DetermineObjectiveCClassDefinitions(std::set* fwd_decls) const; virtual void DetermineForwardDeclarations(std::set* fwd_decls) const; private: diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc index 6731e37a77fe..af13c145a849 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc @@ -234,6 +234,30 @@ void MessageGenerator::DetermineForwardDeclarations(std::set* fwd_decls) } } +void MessageGenerator::DetermineObjectiveCClassDefinitions(std::set* fwd_decls) { + if (!IsMapEntryMessage(descriptor_)) { + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* fieldDescriptor = descriptor_->field(i); + field_generators_.get(fieldDescriptor) + .DetermineObjectiveCClassDefinitions(fwd_decls); + } + } + + for (const auto& generator : extension_generators_) { + generator->DetermineObjectiveCClassDefinitions(fwd_decls); + } + + for (const auto& generator : nested_message_generators_) { + generator->DetermineObjectiveCClassDefinitions(fwd_decls); + } + + const Descriptor* containing_descriptor = descriptor_->containing_type(); + if (containing_descriptor != NULL) { + string containing_class = ClassName(containing_descriptor); + fwd_decls->insert(ObjCClassSymbolDefinition(containing_class)); + } +} + bool MessageGenerator::IncludesOneOfDefinition() const { if (!oneof_generators_.empty()) { return true; @@ -457,11 +481,11 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { field_description_type = "GPBMessageFieldDescription"; } if (has_fields) { - printer->Print( - " static $field_description_type$ fields[] = {\n", - "field_description_type", field_description_type); printer->Indent(); printer->Indent(); + printer->Print( + "static $field_description_type$ fields[] = {\n", + "field_description_type", field_description_type); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); ++i) { const FieldGenerator& field_generator = @@ -474,10 +498,10 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { } } printer->Outdent(); + printer->Print( + "};\n"); printer->Outdent(); printer->Outdent(); - printer->Print( - " };\n"); } std::map vars; @@ -492,6 +516,7 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { } std::vector init_flags; + init_flags.push_back("GPBDescriptorInitializationFlag_UsesClassRefs"); if (need_defaults) { init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault"); } @@ -556,10 +581,11 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); } if (descriptor_->containing_type() != NULL) { - string parent_class_name = ClassName(descriptor_->containing_type()); + string containing_class = ClassName(descriptor_->containing_type()); + string parent_class_ref = ObjCClassSymbolReference(containing_class); printer->Print( - " [localDescriptor setupContainingMessageClassName:GPBStringifySymbol($parent_name$)];\n", - "parent_name", parent_class_name); + " [localDescriptor setupContainingMessageClass:$parent_class_ref$];\n", + "parent_class_ref", parent_class_ref); } string suffix_added; ClassName(descriptor_, &suffix_added); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h index 55eda0b8efe9..138e62020638 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h @@ -63,6 +63,7 @@ class MessageGenerator { void GenerateMessageHeader(io::Printer* printer); void GenerateSource(io::Printer* printer); void GenerateExtensionRegistrationSource(io::Printer* printer); + void DetermineObjectiveCClassDefinitions(std::set* fwd_decls); void DetermineForwardDeclarations(std::set* fwd_decls); // Checks if the message or a nested message includes a oneof definition. diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc index 8a0299e7c2ad..93b75571c2a6 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc @@ -46,13 +46,14 @@ namespace { void SetMessageVariables(const FieldDescriptor* descriptor, std::map* variables) { const string& message_type = ClassName(descriptor->message_type()); + const string& containing_class = ClassName(descriptor->containing_type()); (*variables)["type"] = message_type; - (*variables)["containing_class"] = ClassName(descriptor->containing_type()); + (*variables)["containing_class"] = containing_class; (*variables)["storage_type"] = message_type; (*variables)["group_or_message"] = (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; - - (*variables)["dataTypeSpecific_value"] = "GPBStringifySymbol(" + message_type + ")"; + (*variables)["dataTypeSpecific_value"] = + ObjCClassSymbolReference(message_type); } } // namespace @@ -72,6 +73,11 @@ void MessageFieldGenerator::DetermineForwardDeclarations( fwd_decls->insert("@class " + variable("storage_type")); } +void MessageFieldGenerator::DetermineObjectiveCClassDefinitions( + std::set* fwd_decls) const { + fwd_decls->insert(ObjCClassSymbolDefinition(variable("storage_type"))); +} + bool MessageFieldGenerator::WantsHasProperty(void) const { if (descriptor_->containing_oneof() != NULL) { // If in a oneof, it uses the oneofcase instead of a has bit. @@ -100,6 +106,10 @@ void RepeatedMessageFieldGenerator::DetermineForwardDeclarations( fwd_decls->insert("@class " + variable("storage_type")); } +void RepeatedMessageFieldGenerator::DetermineObjectiveCClassDefinitions( + std::set* fwd_decls) const { + fwd_decls->insert(ObjCClassSymbolDefinition(variable("storage_type"))); +} } // namespace objectivec } // namespace compiler diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h index 98d457942e23..692f94c02614 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h @@ -56,6 +56,7 @@ class MessageFieldGenerator : public ObjCObjFieldGenerator { public: virtual void DetermineForwardDeclarations(std::set* fwd_decls) const; + virtual void DetermineObjectiveCClassDefinitions(std::set* fwd_decls) const; }; class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { @@ -72,6 +73,7 @@ class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { public: virtual void DetermineForwardDeclarations(std::set* fwd_decls) const; + virtual void DetermineObjectiveCClassDefinitions(std::set* fwd_decls) const; }; } // namespace objectivec