messageMemberNames function

MemberNames messageMemberNames(
  1. DescriptorProto descriptor,
  2. String parentClassName,
  3. Set<String> usedTopLevelNames, {
  4. Iterable<String> reserved = const [],
})

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 []}) {
  var fieldList = List<FieldDescriptorProto>.from(descriptor.field);
  var sourcePositions =
      fieldList.asMap().map((index, field) => MapEntry(field.name, index));
  var 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.
  var indexes = <String, int>{};
  for (var field in sorted) {
    var index = indexes.length;
    indexes[field.name] = index;
  }

  var existingNames = <String>{...reservedMemberNames, ...reserved};

  var 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 (var 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 (var field in sorted) {
    if (_nameOption(field)!.isEmpty) {
      var index = indexes[field.name]!;
      var sourcePosition = sourcePositions[field.name];
      takeFieldNames(
          _unusedMemberNames(field, index, sourcePosition, existingNames));
    }
  }

  var 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++) {
    var oneof = descriptor.oneofDecl[i];

    var oneofName = disambiguateName(
        underscoresToCamelCase(oneof.name), existingNames, defaultSuffixes(),
        generateVariants: oneofNameVariants);

    var oneofEnumName =
        oneofEnumClassName(oneof.name, usedTopLevelNames, parentClassName);

    var enumMapName = disambiguateName(
        '_${oneofEnumName}ByTag', existingNames, defaultSuffixes());

    takeOneofNames(OneofNames(oneof, i, _defaultClearMethodName(oneofName),
        _defaultWhichMethodName(oneofName), oneofEnumName, enumMapName));
  }

  return MemberNames(fieldNames.cast<FieldNames>(), oneofNames);
}