messageMemberNames function
Chooses the GeneratedMessage member names for each field and names associated with each oneof declaration.
Additional names to avoid can be supplied using reserved
.
(This should only be used for mixins.)
Returns MemberNames which holds a list with FieldNames and a list with OneofNames.
Throws DartNameOptionException if a field has this option and it's set to an invalid name.
Implementation
MemberNames messageMemberNames(
DescriptorProto descriptor,
String parentClassName,
Set<String> usedTopLevelNames, {
Iterable<String> reserved = const [],
bool lowercaseGroupNames = false,
}) {
final fieldList = List<FieldDescriptorProto>.from(descriptor.field);
final sourcePositions = fieldList.asMap().map(
(index, field) => MapEntry(field.name, index),
);
final sorted =
fieldList..sort((FieldDescriptorProto a, FieldDescriptorProto b) {
if (a.number < b.number) return -1;
if (a.number > b.number) return 1;
throw 'multiple fields defined for tag ${a.number} in ${descriptor.name}';
});
// Choose indexes first, based on their position in the sorted list.
final indexes = <String, int>{};
for (final field in sorted) {
final index = indexes.length;
indexes[field.name] = index;
}
final existingNames = <String>{...reservedMemberNames, ...reserved};
final fieldNames = List<FieldNames?>.filled(indexes.length, null);
void takeFieldNames(FieldNames chosen) {
fieldNames[chosen.index!] = chosen;
existingNames.add(chosen.fieldName);
if (chosen.hasMethodName != null) {
existingNames.add(chosen.hasMethodName!);
}
if (chosen.clearMethodName != null) {
existingNames.add(chosen.clearMethodName!);
}
}
// Handle fields with a dart_name option.
// They have higher priority than automatically chosen names.
// Explicitly setting a name that's already taken is a build error.
for (final field in sorted) {
if (_nameOption(field)!.isNotEmpty) {
takeFieldNames(
_memberNamesFromOption(
descriptor,
field,
indexes[field.name]!,
sourcePositions[field.name]!,
existingNames,
),
);
}
}
// Then do other fields.
// They are automatically renamed until we find something unused.
for (final field in sorted) {
if (_nameOption(field)!.isEmpty) {
final index = indexes[field.name]!;
final sourcePosition = sourcePositions[field.name];
takeFieldNames(
_unusedMemberNames(
field,
index,
sourcePosition,
existingNames,
lowercaseGroupNames,
),
);
}
}
final oneofNames = <OneofNames>[];
void takeOneofNames(OneofNames chosen) {
oneofNames.add(chosen);
existingNames.add(chosen.whichOneofMethodName);
existingNames.add(chosen.clearMethodName);
existingNames.add(chosen.byTagMapName);
}
List<String> oneofNameVariants(String name) {
return [_defaultWhichMethodName(name), _defaultClearMethodName(name)];
}
final realOneofCount = countRealOneofs(descriptor);
for (var i = 0; i < realOneofCount; i++) {
final oneof = descriptor.oneofDecl[i];
final oneofName = disambiguateName(
underscoresToCamelCase(oneof.name),
existingNames,
defaultSuffixes(),
generateVariants: oneofNameVariants,
);
final oneofEnumName = oneofEnumClassName(
oneof.name,
usedTopLevelNames,
parentClassName,
);
final enumMapName = disambiguateName(
'_${oneofEnumName}ByTag',
existingNames,
defaultSuffixes(),
);
takeOneofNames(
OneofNames(
oneof,
i,
_defaultClearMethodName(oneofName),
_defaultWhichMethodName(oneofName),
oneofEnumName,
enumMapName,
),
);
}
return MemberNames(fieldNames.cast<FieldNames>(), oneofNames);
}