diff options
author | Thomas Van Lenten <thomasvl@google.com> | 2016-08-16 11:26:49 -0400 |
---|---|---|
committer | Thomas Van Lenten <thomasvl@google.com> | 2016-09-08 11:59:57 -0400 |
commit | 337ec3065f98d6f048f92b3a864f65383a2549d8 (patch) | |
tree | 23ab2fea2b0d97cc64b0253fd313ce9bad1bbaf9 /objectivec/GPBDescriptor.m | |
parent | 4bc16578537495b5ee010d89f2909858312210ac (diff) | |
download | protobuf-337ec3065f98d6f048f92b3a864f65383a2549d8.tar.gz protobuf-337ec3065f98d6f048f92b3a864f65383a2549d8.tar.bz2 protobuf-337ec3065f98d6f048f92b3a864f65383a2549d8.zip |
Add ObjC helpers for Any WKT.
- Capture the ObjC prefix used when generating the the file.
- Track the containing type on descriptors.
- Mark descriptors where the message class name got a suffix added to it.
- Expose a fullName property on Descriptors.
- Add helpers for packing/unpacking Any messages.
- Bump the ObjC runtime version number. Since we added methods and invoke them
in the generated code, ensure the code is running against a matching version.
Otherwise, someone could compile against headers, but run with a framework
that is older and get unknown selector failures. This should trip clearer
messaging.
Fixes https://github.com/google/protobuf/issues/1674
Diffstat (limited to 'objectivec/GPBDescriptor.m')
-rw-r--r-- | objectivec/GPBDescriptor.m | 114 |
1 files changed, 113 insertions, 1 deletions
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) { |