Browse Source

Add Setter/Getter type verification. (#3880)

Add runtime asserts (that can be disabled in release) that verify
that the types being get/set for messages using the C Api match
the type in the descriptor for the field being get/set.
dmaclach 7 years ago
parent
commit
2b3aa1c294
1 changed files with 285 additions and 7 deletions
  1. 285 7
      objectivec/GPBUtilities.m

+ 285 - 7
objectivec/GPBUtilities.m

@@ -49,6 +49,19 @@ static void AppendTextFormatForMessage(GPBMessage *message,
                                        NSMutableString *toStr,
                                        NSString *lineIndent);
 
+// Are two datatypes the same basic type representation (ex Int32 and SInt32).
+// Marked unused because currently only called from asserts/debug.
+static BOOL DataTypesEquivalent(GPBDataType type1,
+                                GPBDataType type2) __attribute__ ((unused));
+
+// Basic type representation for a type (ex: for SInt32 it is Int32).
+// Marked unused because currently only called from asserts/debug.
+static GPBDataType BaseDataType(GPBDataType type) __attribute__ ((unused));
+
+// String name for a data type.
+// Marked unused because currently only called from asserts/debug.
+static NSString *TypeToString(GPBDataType dataType) __attribute__ ((unused));
+
 NSData *GPBEmptyNSData(void) {
   static dispatch_once_t onceToken;
   static NSData *defaultNSData = nil;
@@ -342,6 +355,14 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
 //%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE)
 //%TYPE GPBGetMessage##NAME##Field(GPBMessage *self,
 //% TYPE$S            NAME$S       GPBFieldDescriptor *field) {
+//%#if defined(DEBUG) && DEBUG
+//%  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+//%                                GPBDataType##NAME),
+//%            @"Attempting to get value of TYPE from field %@ "
+//%            @"of %@ which is of type %@.",
+//%            [self class], field.name,
+//%            TypeToString(GPBGetFieldDataType(field)));
+//%#endif
 //%  if (GPBGetHasIvarField(self, field)) {
 //%    uint8_t *storage = (uint8_t *)self->messageStorage_;
 //%    TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
@@ -364,14 +385,24 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
 //%            NAME$S                     GPBFieldDescriptor *field,
 //%            NAME$S                     TYPE value,
 //%            NAME$S                     GPBFileSyntax syntax) {
+//%#if defined(DEBUG) && DEBUG
+//%  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+//%                                GPBDataType##NAME),
+//%            @"Attempting to set field %@ of %@ which is of type %@ with "
+//%            @"value of type TYPE.",
+//%            [self class], field.name,
+//%            TypeToString(GPBGetFieldDataType(field)));
+//%#endif
 //%  GPBOneofDescriptor *oneof = field->containingOneof_;
 //%  if (oneof) {
 //%    GPBMessageFieldDescription *fieldDesc = field->description_;
 //%    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
 //%  }
+//%#if defined(DEBUG) && DEBUG
 //%  NSCAssert(self->messageStorage_ != NULL,
 //%            @"%@: All messages should have storage (from init)",
 //%            [self class]);
+//%#endif
 //%#if defined(__clang_analyzer__)
 //%  if (self->messageStorage_ == NULL) return;
 //%#endif
@@ -391,6 +422,14 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
 //%// Only exists for public api, no core code should use this.
 //%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self,
 //% TYPE$S             NAME$S       GPBFieldDescriptor *field) {
+//%#if defined(DEBUG) && DEBUG
+//%  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+//%                                GPBDataType##NAME),
+//%            @"Attempting to get value of TYPE from field %@ "
+//%            @"of %@ which is of type %@.",
+//%            [self class], field.name,
+//%            TypeToString(GPBGetFieldDataType(field)));
+//%#endif
 //%  return (TYPE *)GPBGetObjectIvarWithField(self, field);
 //%}
 //%
@@ -398,6 +437,14 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
 //%void GPBSetMessage##NAME##Field(GPBMessage *self,
 //%                   NAME$S     GPBFieldDescriptor *field,
 //%                   NAME$S     TYPE *value) {
+//%#if defined(DEBUG) && DEBUG
+//%  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+//%                                GPBDataType##NAME),
+//%            @"Attempting to set field %@ of %@ which is of type %@ with "
+//%            @"value of type TYPE.",
+//%            [self class], field.name,
+//%            TypeToString(GPBGetFieldDataType(field)));
+//%#endif
 //%  GPBSetObjectIvarWithField(self, field, (id)value);
 //%}
 //%
@@ -455,7 +502,7 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
   GPBDataType fieldType = GPBGetFieldDataType(field);
   BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
   BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType);
-#ifdef DEBUG
+#if defined(DEBUG) && DEBUG
   if (value == nil && !isMapOrArray && !fieldIsMessage &&
       field.hasDefaultValue) {
     // Setting a message to nil is an obvious way to "clear" the value
@@ -618,6 +665,13 @@ int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
 int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
                                         GPBFieldDescriptor *field,
                                         GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
+            @"Attempting to get value of type Enum from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   int32_t result = GPBGetMessageInt32Field(self, field);
   // If this is presevering unknown enums, make sure the value is valid before
   // returning it.
@@ -638,6 +692,13 @@ void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
 void GPBSetEnumIvarWithFieldInternal(GPBMessage *self,
                                      GPBFieldDescriptor *field, int32_t value,
                                      GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type Enum.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   // Don't allow in unknown values.  Proto3 can use the Raw method.
   if (![field isValidEnumValue:value]) {
     [NSException raise:NSInvalidArgumentException
@@ -663,6 +724,13 @@ void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field,
 
 BOOL GPBGetMessageBoolField(GPBMessage *self,
                             GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
+            @"Attempting to get value of type bool from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   if (GPBGetHasIvarField(self, field)) {
     // Bools are stored in the has bits to avoid needing explicit space in the
     // storage structure.
@@ -688,6 +756,13 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
                                      GPBFieldDescriptor *field,
                                      BOOL value,
                                      GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type bool.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBMessageFieldDescription *fieldDesc = field->description_;
   GPBOneofDescriptor *oneof = field->containingOneof_;
   if (oneof) {
@@ -714,6 +789,14 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
 
 int32_t GPBGetMessageInt32Field(GPBMessage *self,
                                 GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeInt32),
+            @"Attempting to get value of int32_t from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   if (GPBGetHasIvarField(self, field)) {
     uint8_t *storage = (uint8_t *)self->messageStorage_;
     int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
@@ -736,14 +819,24 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
                                       GPBFieldDescriptor *field,
                                       int32_t value,
                                       GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeInt32),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type int32_t.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBOneofDescriptor *oneof = field->containingOneof_;
   if (oneof) {
     GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
+#if defined(DEBUG) && DEBUG
   NSCAssert(self->messageStorage_ != NULL,
             @"%@: All messages should have storage (from init)",
             [self class]);
+#endif
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -764,6 +857,14 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
 
 uint32_t GPBGetMessageUInt32Field(GPBMessage *self,
                                   GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeUInt32),
+            @"Attempting to get value of uint32_t from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   if (GPBGetHasIvarField(self, field)) {
     uint8_t *storage = (uint8_t *)self->messageStorage_;
     uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
@@ -786,14 +887,24 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
                                        GPBFieldDescriptor *field,
                                        uint32_t value,
                                        GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeUInt32),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type uint32_t.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBOneofDescriptor *oneof = field->containingOneof_;
   if (oneof) {
     GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
+#if defined(DEBUG) && DEBUG
   NSCAssert(self->messageStorage_ != NULL,
             @"%@: All messages should have storage (from init)",
             [self class]);
+#endif
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -814,6 +925,14 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
 
 int64_t GPBGetMessageInt64Field(GPBMessage *self,
                                 GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeInt64),
+            @"Attempting to get value of int64_t from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   if (GPBGetHasIvarField(self, field)) {
     uint8_t *storage = (uint8_t *)self->messageStorage_;
     int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
@@ -836,14 +955,24 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
                                       GPBFieldDescriptor *field,
                                       int64_t value,
                                       GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeInt64),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type int64_t.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBOneofDescriptor *oneof = field->containingOneof_;
   if (oneof) {
     GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
+#if defined(DEBUG) && DEBUG
   NSCAssert(self->messageStorage_ != NULL,
             @"%@: All messages should have storage (from init)",
             [self class]);
+#endif
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -864,6 +993,14 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
 
 uint64_t GPBGetMessageUInt64Field(GPBMessage *self,
                                   GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeUInt64),
+            @"Attempting to get value of uint64_t from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   if (GPBGetHasIvarField(self, field)) {
     uint8_t *storage = (uint8_t *)self->messageStorage_;
     uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
@@ -886,14 +1023,24 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
                                        GPBFieldDescriptor *field,
                                        uint64_t value,
                                        GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeUInt64),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type uint64_t.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBOneofDescriptor *oneof = field->containingOneof_;
   if (oneof) {
     GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
+#if defined(DEBUG) && DEBUG
   NSCAssert(self->messageStorage_ != NULL,
             @"%@: All messages should have storage (from init)",
             [self class]);
+#endif
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -914,6 +1061,14 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
 
 float GPBGetMessageFloatField(GPBMessage *self,
                               GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeFloat),
+            @"Attempting to get value of float from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   if (GPBGetHasIvarField(self, field)) {
     uint8_t *storage = (uint8_t *)self->messageStorage_;
     float *typePtr = (float *)&storage[field->description_->offset];
@@ -936,14 +1091,24 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
                                       GPBFieldDescriptor *field,
                                       float value,
                                       GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeFloat),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type float.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBOneofDescriptor *oneof = field->containingOneof_;
   if (oneof) {
     GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
+#if defined(DEBUG) && DEBUG
   NSCAssert(self->messageStorage_ != NULL,
             @"%@: All messages should have storage (from init)",
             [self class]);
+#endif
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -964,6 +1129,14 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
 
 double GPBGetMessageDoubleField(GPBMessage *self,
                                 GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeDouble),
+            @"Attempting to get value of double from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   if (GPBGetHasIvarField(self, field)) {
     uint8_t *storage = (uint8_t *)self->messageStorage_;
     double *typePtr = (double *)&storage[field->description_->offset];
@@ -986,14 +1159,24 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
                                        GPBFieldDescriptor *field,
                                        double value,
                                        GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeDouble),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type double.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBOneofDescriptor *oneof = field->containingOneof_;
   if (oneof) {
     GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
+#if defined(DEBUG) && DEBUG
   NSCAssert(self->messageStorage_ != NULL,
             @"%@: All messages should have storage (from init)",
             [self class]);
+#endif
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -1019,6 +1202,14 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
 // Only exists for public api, no core code should use this.
 NSString *GPBGetMessageStringField(GPBMessage *self,
                                    GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeString),
+            @"Attempting to get value of NSString from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   return (NSString *)GPBGetObjectIvarWithField(self, field);
 }
 
@@ -1026,6 +1217,14 @@ NSString *GPBGetMessageStringField(GPBMessage *self,
 void GPBSetMessageStringField(GPBMessage *self,
                               GPBFieldDescriptor *field,
                               NSString *value) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeString),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type NSString.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBSetObjectIvarWithField(self, field, (id)value);
 }
 
@@ -1035,6 +1234,14 @@ void GPBSetMessageStringField(GPBMessage *self,
 // Only exists for public api, no core code should use this.
 NSData *GPBGetMessageBytesField(GPBMessage *self,
                                 GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeBytes),
+            @"Attempting to get value of NSData from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   return (NSData *)GPBGetObjectIvarWithField(self, field);
 }
 
@@ -1042,6 +1249,14 @@ NSData *GPBGetMessageBytesField(GPBMessage *self,
 void GPBSetMessageBytesField(GPBMessage *self,
                              GPBFieldDescriptor *field,
                              NSData *value) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeBytes),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type NSData.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBSetObjectIvarWithField(self, field, (id)value);
 }
 
@@ -1051,6 +1266,14 @@ void GPBSetMessageBytesField(GPBMessage *self,
 // Only exists for public api, no core code should use this.
 GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
                                       GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeMessage),
+            @"Attempting to get value of GPBMessage from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
 }
 
@@ -1058,6 +1281,14 @@ GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
 void GPBSetMessageMessageField(GPBMessage *self,
                                GPBFieldDescriptor *field,
                                GPBMessage *value) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeMessage),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type GPBMessage.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBSetObjectIvarWithField(self, field, (id)value);
 }
 
@@ -1067,6 +1298,14 @@ void GPBSetMessageMessageField(GPBMessage *self,
 // Only exists for public api, no core code should use this.
 GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
                                     GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeGroup),
+            @"Attempting to get value of GPBMessage from field %@ "
+            @"of %@ which is of type %@.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
 }
 
@@ -1074,6 +1313,14 @@ GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
 void GPBSetMessageGroupField(GPBMessage *self,
                              GPBFieldDescriptor *field,
                              GPBMessage *value) {
+#if defined(DEBUG) && DEBUG
+  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+                                GPBDataTypeGroup),
+            @"Attempting to set field %@ of %@ which is of type %@ with "
+            @"value of type GPBMessage.",
+            [self class], field.name,
+            TypeToString(GPBGetFieldDataType(field)));
+#endif
   GPBSetObjectIvarWithField(self, field, (id)value);
 }
 
@@ -1137,8 +1384,40 @@ void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id
   GPBSetObjectIvarWithField(self, field, array);
 }
 
-#if defined(DEBUG) && DEBUG
-static NSString *TypeToStr(GPBDataType dataType) {
+static GPBDataType BaseDataType(GPBDataType type) {
+  switch (type) {
+    case GPBDataTypeSFixed32:
+    case GPBDataTypeInt32:
+    case GPBDataTypeSInt32:
+    case GPBDataTypeEnum:
+      return GPBDataTypeInt32;
+    case GPBDataTypeFixed32:
+    case GPBDataTypeUInt32:
+      return GPBDataTypeUInt32;
+    case GPBDataTypeSFixed64:
+    case GPBDataTypeInt64:
+    case GPBDataTypeSInt64:
+      return GPBDataTypeInt64;
+    case GPBDataTypeFixed64:
+    case GPBDataTypeUInt64:
+      return GPBDataTypeUInt64;
+    case GPBDataTypeMessage:
+    case GPBDataTypeGroup:
+      return GPBDataTypeMessage;
+    case GPBDataTypeBool:
+    case GPBDataTypeFloat:
+    case GPBDataTypeDouble:
+    case GPBDataTypeBytes:
+    case GPBDataTypeString:
+      return type;
+   }
+}
+
+static BOOL DataTypesEquivalent(GPBDataType type1, GPBDataType type2) {
+  return BaseDataType(type1) == BaseDataType(type2);
+}
+
+static NSString *TypeToString(GPBDataType dataType) {
   switch (dataType) {
     case GPBDataTypeBool:
       return @"Bool";
@@ -1166,10 +1445,9 @@ static NSString *TypeToStr(GPBDataType dataType) {
     case GPBDataTypeGroup:
       return @"Object";
     case GPBDataTypeEnum:
-      return @"Bool";
+      return @"Enum";
   }
 }
-#endif
 
 // GPBGetMessageMapField is defined in GPBMessage.m
 
@@ -1185,8 +1463,8 @@ void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
   if (dictionary) {
     GPBDataType keyDataType = field.mapKeyDataType;
     GPBDataType valueDataType = GPBGetFieldDataType(field);
-    NSString *keyStr = TypeToStr(keyDataType);
-    NSString *valueStr = TypeToStr(valueDataType);
+    NSString *keyStr = TypeToString(keyDataType);
+    NSString *valueStr = TypeToString(valueDataType);
     if (keyDataType == GPBDataTypeString) {
       keyStr = @"String";
     }