// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/src/binary/binary_reader.dart'; import 'package:analyzer/src/binary/binary_writer.dart'; import 'package:analyzer/src/utilities/extensions/string.dart'; /// The base name of an element. /// /// In contrast to [LookupName] there is no `=` at the end. extension type BaseName(String _it) { factory BaseName.read(BinaryReader reader) { var str = reader.readStringReference(); return BaseName(str); } /// Returns the underlying [String] value, explicitly. String get asString => _it; void write(BinaryWriter writer) { writer.writeStringReference(_it); } static int compare(BaseName left, BaseName right) { return left._it.compareTo(right._it); } } /// The lookup name of an element. /// /// Specifically, for setters there is `=` at the end. extension type LookupName(String _it) { factory LookupName.read(BinaryReader reader) { var str = reader.readStringReference(); return LookupName(str); } BaseName get asBaseName { if (const {'==', '<=', '>='}.contains(_it)) { return _it.asBaseName; } if (_it == '[]=') { return '[]'.asBaseName; } var str = _it.removeSuffix('=') ?? _it; return str.asBaseName; } /// Returns the underlying [String] value, explicitly. String get asString => _it; bool get isIndexEq { return _it == '[]='; } bool get isIndexOrIndexEq { return const {'[]', '[]='}.contains(_it); } bool get isOperator { return const { ...{'+', '-', '*', '/', '~/', '%'}, ...{'<<', '>>', '>>>', '&', '^', '|', '~'}, ...{'<', '<=', '>', '>=', '=='}, 'unary-', }.contains(_it); } bool get isPrivate => _it.startsWith('_'); bool get isSetter { return _it.endsWith('=') && !const {'==', '<=', '>=', '[]='}.contains(_it); } /// This name must be a name of a method. LookupName get methodToSetter { assert(!isSetter); if (isOperator || isIndexOrIndexEq) { return this; } return LookupName('$_it='); } List get relatedNames { if (isOperator) { return [this]; } if (isIndexOrIndexEq) { return ['[]'.asLookupName, '[]='.asLookupName]; } if (isSetter) { return [this, setterToGetter]; } var setterName = '$_it='; return [this, setterName.asLookupName]; } /// This name must be a name of a setter. LookupName get setterToGetter { assert(isSetter); assert(_it.endsWith('=')); return _it.substring(0, _it.length - 1).asLookupName; } void write(BinaryWriter writer) { writer.writeStringReference(_it); } static int compare(LookupName left, LookupName right) { return left._it.compareTo(right._it); } } extension BinaryReaderExtension on BinaryReader { Set readBaseNameSet() { var length = readUint30(); var result = {}; for (var i = 0; i < length; i++) { var baseName = BaseName.read(this); result.add(baseName); } return result; } List readLookupNameList() { return readTypedList(() => LookupName.read(this)); } Set readLookupNameSet() { var length = readUint30(); var result = {}; for (var i = 0; i < length; i++) { var lookupName = LookupName.read(this); result.add(lookupName); } return result; } } extension BinaryWriterExtension on BinaryWriter { void writeBaseNameIterable(Iterable names) { writeUint30(names.length); for (var baseName in names) { baseName.write(this); } } } extension IterableOfBaseNameExtension on Iterable { List sorted() => [...this]..sort(BaseName.compare); } extension IterableOfStringExtension on Iterable { Set toBaseNameSet() { return map((str) => str.asBaseName).toSet(); } } extension LookupNameIterableExtension on Iterable { void write(BinaryWriter writer) { writer.writeIterable(this, (name) => name.write(writer)); } } extension StringExtension on String { BaseName get asBaseName { return BaseName(this); } LookupName get asLookupName { return LookupName(this); } }