|  | @@ -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,12 +349,26 @@ 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];
 | 
	
	
		
			
				|  | @@ -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) {
 |