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 []}) {
  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));
    }
  }

  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);
}