// Copyright (c) 2016, 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.

library;

import 'package:kernel/ast.dart' as ir;

import '../common.dart';
import '../common/elements.dart' show ElementEnvironment;
import '../elements/entities.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../ir/annotations.dart';
import '../js_model/js_to_frontend_map.dart' show identity, JsToFrontendMap;
import '../kernel/element_map.dart';
import '../native/behavior.dart' show NativeBehavior;
import '../serialization/serialization.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import '../util/util.dart';

class NativeBasicDataBuilder {
  bool _closed = false;

  /// Tag info for native JavaScript classes names. See
  /// [setNativeClassTagInfo].
  final Map<ClassEntity, NativeClassTag> _nativeClassTagInfo = {};

  /// The JavaScript libraries implemented via typed JavaScript interop.
  final Map<LibraryEntity, String> _jsInteropLibraries = {};

  /// The JavaScript classes implemented via typed JavaScript interop.
  final Map<ClassEntity, String> _jsInteropClasses = {};

  /// JavaScript interop classes annotated with `@anonymous`.
  final Set<ClassEntity> _anonymousJsInteropClasses = {};

  /// JavaScript interop classes annotated with `@staticInterop`.
  final Set<ClassEntity> _staticInteropClasses = {};

  /// The JavaScript members implemented via typed JavaScript interop.
  final Map<MemberEntity, String> _jsInteropMembers = {};

  /// Sets the native tag info for [cls].
  ///
  /// The tag info string contains comma-separated 'words' which are either
  /// dispatch tags (having JavaScript identifier syntax) and directives that
  /// begin with `!`.
  void setNativeClassTagInfo(ClassEntity cls, String tagText) {
    assert(
      !_closed,
      failedAt(
        cls,
        "NativeBasicDataBuilder is closed. "
        "Trying to mark $cls as a native class.",
      ),
    );

    // TODO(johnniwinther): Assert that this is only called once. The memory
    // compiler copies pre-processed elements into a new compiler through
    // [Compiler.onLibraryScanned] and thereby causes multiple calls to this
    // method.
    assert(
      !_nativeClassTagInfo.containsKey(cls) ||
          _nativeClassTagInfo[cls]!.text == tagText,
      failedAt(
        cls,
        "Native tag info set inconsistently on $cls: "
        "Existing tag info '${_nativeClassTagInfo[cls]}', "
        "new tag info '$tagText'.",
      ),
    );
    _nativeClassTagInfo[cls] = NativeClassTag(tagText);
  }

  /// Marks [element] as an explicit part of js interop.
  ///
  /// If [name] is provided, it sets the explicit js interop name for the
  /// library [element], other the js interop name is expected to be computed
  /// later.
  void markAsJsInteropLibrary(LibraryEntity element, {required String name}) {
    assert(
      !_closed,
      failedAt(
        element,
        "NativeBasicDataBuilder is closed. "
        "Trying to mark $element as a js-interop library.",
      ),
    );
    _jsInteropLibraries[element] = name;
  }

  /// Marks [element] as an explicit part of js interop.
  ///
  /// If [name] is provided, it sets the explicit js interop name for the
  /// class [element], other the js interop name is expected to be computed
  /// later.
  void markAsJsInteropClass(
    ClassEntity element, {
    required String name,
    required bool isAnonymous,
    required bool isStaticInterop,
  }) {
    assert(
      !_closed,
      failedAt(
        element,
        "NativeBasicDataBuilder is closed. "
        "Trying to mark $element as a js-interop class.",
      ),
    );
    _jsInteropClasses[element] = name;
    if (isAnonymous) {
      _anonymousJsInteropClasses.add(element);
    }
    if (isStaticInterop) {
      _staticInteropClasses.add(element);
    }
  }

  /// Marks [element] as an explicit part of js interop and sets the explicit js
  /// interop [name] for the member [element].
  void markAsJsInteropMember(MemberEntity element, String name) {
    assert(
      !_closed,
      failedAt(
        element,
        "NativeBasicDataBuilder is closed. "
        "Trying to mark $element as a js-interop member.",
      ),
    );
    _jsInteropMembers[element] = name;
  }

  /// Creates the [NativeBasicData] object for the data collected in this
  /// builder.
  NativeBasicData close(ElementEnvironment environment) {
    _closed = true;
    return NativeBasicData(
      environment,
      false,
      _nativeClassTagInfo,
      _jsInteropLibraries,
      _jsInteropClasses,
      _anonymousJsInteropClasses,
      _staticInteropClasses,
      _jsInteropMembers,
    );
  }

  void reopenForTesting() {
    _closed = false;
  }
}

/// Basic information for native classes and js-interop libraries and classes.
///
/// This information is computed during loading using [NativeBasicDataBuilder].
class NativeBasicData {
  /// Tag used for identifying serialized [NativeBasicData] objects in a
  /// debugging data stream.
  static const String tag = 'native-basic-data';

  final ElementEnvironment _env;

  bool _isAllowInteropUsed;

  /// Tag info for native JavaScript classes names. See
  /// [setNativeClassTagInfo].
  final Map<ClassEntity, NativeClassTag> _nativeClassTagInfo;

  /// The JavaScript libraries implemented via typed JavaScript interop.
  final Map<LibraryEntity, String> _jsInteropLibraries;

  /// The JavaScript classes implemented via typed JavaScript interop.
  final Map<ClassEntity, String> _jsInteropClasses;

  /// JavaScript interop classes annotated with `@anonymous`
  final Set<ClassEntity> _anonymousJsInteropClasses;

  /// JavaScript interop classes annotated with `@staticInterop`
  final Set<ClassEntity> _staticInteropClasses;

  /// The JavaScript members implemented via typed JavaScript interop.
  final Map<MemberEntity, String?> _jsInteropMembers;

  NativeBasicData(
    this._env,
    this._isAllowInteropUsed,
    this._nativeClassTagInfo,
    this._jsInteropLibraries,
    this._jsInteropClasses,
    this._anonymousJsInteropClasses,
    this._staticInteropClasses,
    this._jsInteropMembers,
  );

  factory NativeBasicData.fromIr(
    KernelToElementMap map,
    IrAnnotationData data,
  ) {
    ElementEnvironment env = map.elementEnvironment;
    Map<ClassEntity, NativeClassTag> nativeClassTagInfo = {};
    Map<LibraryEntity, String> jsInteropLibraries = {};
    Map<ClassEntity, String> jsInteropClasses = {};
    Set<ClassEntity> anonymousJsInteropClasses = {};
    Set<ClassEntity> staticInteropClasses = {};
    Map<MemberEntity, String?> jsInteropMembers = {};

    data.forEachNativeClass((ir.Class node, String text) {
      nativeClassTagInfo[map.getClass(node)] = NativeClassTag(text);
    });
    data.forEachJsInteropLibrary((ir.Library node, String name) {
      jsInteropLibraries[env.lookupLibrary(node.importUri, required: true)!] =
          name;
    });
    data.forEachJsInteropClass((
      ir.Class node,
      String name, {
      required bool isAnonymous,
      required bool isStaticInterop,
    }) {
      ClassEntity cls = map.getClass(node);
      jsInteropClasses[cls] = name;
      if (isAnonymous) {
        anonymousJsInteropClasses.add(cls);
      }
      if (isStaticInterop) {
        staticInteropClasses.add(cls);
      }
    });
    data.forEachJsInteropMember((ir.Member node, String? name) {
      // TODO(49428): Are there other members that we should ignore here?
      //  There are non-external and unannotated members because the source code
      //  doesn't contain them. (e.g. default constructor) Does it make sense to
      //  consider these valid JS members?
      if (memberIsIgnorable(node)) return;
      jsInteropMembers[map.getMember(node)] = name;
    });

    return NativeBasicData(
      env,
      false,
      nativeClassTagInfo,
      jsInteropLibraries,
      jsInteropClasses,
      anonymousJsInteropClasses,
      staticInteropClasses,
      jsInteropMembers,
    );
  }

  /// Deserializes a [NativeBasicData] object from [source].
  factory NativeBasicData.readFromDataSource(
    DataSourceReader source,
    ElementEnvironment elementEnvironment,
  ) {
    source.begin(tag);
    bool isAllowInteropUsed = source.readBool();
    Map<ClassEntity, NativeClassTag> nativeClassTagInfo = source.readClassMap(
      () {
        final names = source.readStrings();
        bool isNonLeaf = source.readBool();
        return NativeClassTag.internal(names, isNonLeaf);
      },
    );
    Map<LibraryEntity, String> jsInteropLibraries = source.readLibraryMap(
      source.readString,
    );
    Map<ClassEntity, String> jsInteropClasses = source.readClassMap(
      source.readString,
    );
    Set<ClassEntity> anonymousJsInteropClasses = source.readClasses().toSet();
    Set<ClassEntity> staticInteropClasses = source.readClasses().toSet();
    Map<MemberEntity, String?> jsInteropMembers = source.readMemberMap(
      (MemberEntity member) => source.readStringOrNull(),
    );
    source.end(tag);
    return NativeBasicData(
      elementEnvironment,
      isAllowInteropUsed,
      nativeClassTagInfo,
      jsInteropLibraries,
      jsInteropClasses,
      anonymousJsInteropClasses,
      staticInteropClasses,
      jsInteropMembers,
    );
  }

  /// Serializes this [NativeBasicData] to [sink].
  void writeToDataSink(DataSinkWriter sink) {
    sink.begin(tag);
    sink.writeBool(isAllowInteropUsed);
    sink.writeClassMap(_nativeClassTagInfo, (NativeClassTag tag) {
      sink.writeStrings(tag.names);
      sink.writeBool(tag.isNonLeaf);
    });
    sink.writeLibraryMap(_jsInteropLibraries, sink.writeString);
    sink.writeClassMap(_jsInteropClasses, sink.writeString);
    sink.writeClasses(_anonymousJsInteropClasses);
    sink.writeClasses(_staticInteropClasses);
    sink.writeMemberMap(
      _jsInteropMembers,
      (MemberEntity member, String? name) => sink.writeStringOrNull(name),
    );
    sink.end(tag);
  }

  /// Returns `true` if `allowInterop()` is invoked.
  bool get isAllowInteropUsed => _isAllowInteropUsed;

  /// Marks `allowInterop()` as used.
  ///
  /// [isAllowInteropUsed] is initially false on the closed world, and is only
  /// set during codegen enqueuing.
  void registerAllowInterop() {
    _isAllowInteropUsed = true;
  }

  /// Returns `true` if [cls] corresponds to a native JavaScript class.
  ///
  /// A class is marked as native either through the `@Native(...)` annotation
  /// allowed for internal libraries or via the typed JavaScriptInterop
  /// mechanism allowed for user libraries.
  bool isNativeClass(ClassEntity element) {
    if (isJsInteropClass(element)) return true;
    return _nativeClassTagInfo.containsKey(element);
  }

  /// Returns the list of non-directive native tag words for [cls].
  List<String> getNativeTagsOfClass(ClassEntity cls) {
    return _nativeClassTagInfo[cls]!.names;
  }

  /// Returns `true` if [cls] has a `!nonleaf` tag word.
  bool hasNativeTagsForcedNonLeaf(ClassEntity cls) {
    return _nativeClassTagInfo[cls]!.isNonLeaf;
  }

  /// Returns `true` if js interop features are used.
  bool get isJsInteropUsed =>
      _jsInteropLibraries.isNotEmpty || _jsInteropClasses.isNotEmpty;

  /// Returns `true` if [element] is a JsInterop library.
  bool isJsInteropLibrary(LibraryEntity element) {
    return _jsInteropLibraries.containsKey(element);
  }

  /// Returns `true` if [element] is a JsInterop class.
  bool isJsInteropClass(ClassEntity element) {
    return _jsInteropClasses.containsKey(element);
  }

  /// Returns `true` if [element] is explicitly marked as part of JsInterop.
  bool _isJsInteropMember(MemberEntity element) {
    return _jsInteropMembers.containsKey(element);
  }

  /// Returns `true` if [element] is a JsInterop member.
  bool isJsInteropMember(MemberEntity element) {
    // TODO(johnniwinther): Share this with [NativeData.isJsInteropMember].
    if (element.isFunction ||
        element is ConstructorEntity ||
        element.isGetter ||
        element.isSetter) {
      final function = element as FunctionEntity;
      if (!function.isExternal) return false;

      if (_isJsInteropMember(function)) return true;
      if (function.enclosingClass != null) {
        return isJsInteropClass(function.enclosingClass!);
      }
      if (function.isTopLevel) {
        return isJsInteropLibrary(function.library);
      }
      return false;
    } else {
      return _isJsInteropMember(element);
    }
  }

  /// Returns `true` if [element] or any of its superclasses is native. Supports
  /// nullable element for checks on nonexistent enclosing class of top-level
  /// functions.
  bool isNativeOrExtendsNative(ClassEntity? element) {
    if (element == null) return false;
    if (isNativeClass(element) || isJsInteropClass(element)) {
      return true;
    }
    return isNativeOrExtendsNative(_env.getSuperClass(element));
  }

  NativeBasicData convert(JsToFrontendMap map, ElementEnvironment environment) {
    Map<ClassEntity, NativeClassTag> nativeClassTagInfo =
        <ClassEntity, NativeClassTag>{};
    _nativeClassTagInfo.forEach((ClassEntity cls, NativeClassTag tag) {
      final backendClass = map.toBackendClass(cls);
      nativeClassTagInfo[backendClass] = tag;
    });
    Map<LibraryEntity, String> jsInteropLibraries = map.toBackendLibraryMap(
      _jsInteropLibraries,
      identity,
    );
    Map<ClassEntity, String> jsInteropClasses = map.toBackendClassMap(
      _jsInteropClasses,
      identity,
    );
    Set<ClassEntity> anonymousJsInteropClasses = map.toBackendClassSet(
      _anonymousJsInteropClasses,
    );
    Set<ClassEntity> staticInteropClasses = map.toBackendClassSet(
      _staticInteropClasses,
    );
    Map<MemberEntity, String?> jsInteropMembers = map.toBackendMemberMap(
      _jsInteropMembers,
      identity,
    );
    return NativeBasicData(
      environment,
      isAllowInteropUsed,
      nativeClassTagInfo,
      jsInteropLibraries,
      jsInteropClasses,
      anonymousJsInteropClasses,
      staticInteropClasses,
      jsInteropMembers,
    );
  }
}

class NativeDataBuilder {
  final NativeBasicData _nativeBasicData;

  /// The JavaScript names for native JavaScript elements implemented.
  final Map<MemberEntity, String> _nativeMemberName = {};

  /// Cache for [NativeBehavior]s for calling native methods.
  final Map<FunctionEntity, NativeBehavior> _nativeMethodBehavior = {};

  /// Cache for [NativeBehavior]s for reading from native fields.
  final Map<MemberEntity, NativeBehavior> _nativeFieldLoadBehavior = {};

  /// Cache for [NativeBehavior]s for writing to native fields.
  final Map<MemberEntity, NativeBehavior> _nativeFieldStoreBehavior = {};

  NativeDataBuilder(this._nativeBasicData);

  /// Sets the native [name] for the member [element].
  ///
  /// This name is used for [element] in the generated JavaScript.
  void setNativeMemberName(MemberEntity element, String name) {
    // TODO(johnniwinther): Avoid setting this more than once. The enqueuer
    // might enqueue [element] several times (before processing it) and computes
    // name on each call to `internalAddToWorkList`.
    assert(
      !_nativeMemberName.containsKey(element) ||
          _nativeMemberName[element] == name,
      failedAt(
        element,
        "Native member name set inconsistently on $element: "
        "Existing name '${_nativeMemberName[element]}', "
        "new name '$name'.",
      ),
    );
    _nativeMemberName[element] = name;
  }

  /// Registers the [behavior] for calling the native [method].
  void setNativeMethodBehavior(FunctionEntity method, NativeBehavior behavior) {
    _nativeMethodBehavior[method] = behavior;
  }

  /// Registers the [behavior] for reading from the native [field].
  void setNativeFieldLoadBehavior(FieldEntity field, NativeBehavior behavior) {
    _nativeFieldLoadBehavior[field] = behavior;
  }

  /// Registers the [behavior] for writing to the native [field].
  void setNativeFieldStoreBehavior(FieldEntity field, NativeBehavior behavior) {
    _nativeFieldStoreBehavior[field] = behavior;
  }

  /// Closes this builder and creates the resulting [NativeData] object.
  NativeData close(DiagnosticReporter reporter) {
    final data = NativeData(
      _nativeBasicData,
      _nativeMemberName,
      _nativeMethodBehavior,
      _nativeFieldLoadBehavior,
      _nativeFieldStoreBehavior,
      {},
    );

    if (reporter.options.interopNullAssertions) {
      // We can enforce the return type nullability of an interop API in two
      // ways: by putting the null check on the invocation in the caller, or by
      // putting the null check on the return value in the callee body
      // (generally an interceptor method). It is only safe to do the latter if
      // all interop bindings that share the interceptor method have consistent
      // nullabilities.

      final environment = _nativeBasicData._env;
      final dartTypes = environment.elementMap.commonElements.dartTypes;

      bool returnTypeIsNonNullable(
        FunctionEntity member, {
        required bool callthrough,
      }) {
        final memberType = environment.getFunctionType(member);
        final functionType = callthrough
            ? memberType.returnType as FunctionType
            : memberType;
        return dartTypes.isNonNullable(functionType.returnType);
      }

      // Intercepted methods keyed by selector.
      final jsNameMap = <Selector, List<FunctionEntity>>{};
      for (final (member as FunctionEntity)
          in _nativeBasicData._jsInteropMembers.keys) {
        if (!member.isInstanceMember) continue;
        if (!member.isFunction && !member.isGetter) continue;

        // The program builder uses the unescaped name for interceptor methods.
        // We can only perform null checks in the interceptor method body if all
        // the intercepted methods with the same name have consistent return
        // type nullabilities.
        // We use a public name because the interceptor will not distinguish
        // methods from different libraries, even if they have a leading
        // underscore.
        final name = PublicName(
          data.computeUnescapedJSInteropName(member.name!),
        );

        void addAllPossibleInvocations(FunctionType type) {
          final requiredPositionalCount = type.parameterTypes.length;
          final optionalPositionalCount = type.optionalParameterTypes.length;
          // We do not yet know which invocations are actually live in the
          // program, so we conservatively allow for any number of optional
          // arguments to be passed. Named parameters are not supported.
          for (var i = 0; i <= optionalPositionalCount; i++) {
            (jsNameMap[Selector.call(
                      name,
                      CallStructure.unnamed(requiredPositionalCount + i),
                    )] ??=
                    [])
                .add(member);
          }
        }

        if (member.isGetter) {
          (jsNameMap[Selector.getter(name)] ??= []).add(member);
          final returnType = environment.getFunctionType(member).returnType;
          if (returnType is FunctionType) {
            addAllPossibleInvocations(returnType);
          }
        } else if (member.isFunction) {
          final functionType = environment.getFunctionType(member);
          addAllPossibleInvocations(functionType);
        }
      }

      jsNameMap.forEach((selector, members) {
        final canCheckInCallee = members.every(
          (FunctionEntity member) => returnTypeIsNonNullable(
            member,
            callthrough: member.isGetter && selector.kind == SelectorKind.call,
          ),
        );
        data.interopNullChecks[selector] = canCheckInCallee
            ? InteropNullCheckKind.calleeCheck
            : InteropNullCheckKind.callerCheck;
      });
    }

    return data;
  }
}

enum InteropNullCheckKind { calleeCheck, callerCheck }

/// Additional element information for native classes and methods and js-interop
/// methods.
///
/// This information is computed during resolution using [NativeDataBuilder].
// TODO(johnniwinther): Remove fields that overlap with [NativeBasicData], like
// [anonymousJsInteropClasses].
class NativeData implements NativeBasicData {
  /// Tag used for identifying serialized [NativeData] objects in a
  /// debugging data stream.
  static const String tag = 'native-data';

  /// Prefix used to escape JS names that are not valid Dart names
  /// when using JSInterop.
  static const String _jsInteropEscapePrefix = r'JS$';

  final NativeBasicData _nativeBasicData;

  /// The JavaScript names for native JavaScript elements implemented.
  final Map<MemberEntity, String> _nativeMemberName;

  /// Cache for [NativeBehavior]s for calling native methods.
  final Map<FunctionEntity, NativeBehavior> _nativeMethodBehavior;

  /// Cache for [NativeBehavior]s for reading from native fields.
  final Map<MemberEntity, NativeBehavior> _nativeFieldLoadBehavior;

  /// Cache for [NativeBehavior]s for writing to native fields.
  final Map<MemberEntity, NativeBehavior> _nativeFieldStoreBehavior;

  /// A map from selectors for interop members to the type of null check
  /// required when `--interop-null-assertions` is passed.
  final Map<Selector, InteropNullCheckKind> interopNullChecks;

  NativeData(
    this._nativeBasicData,
    this._nativeMemberName,
    this._nativeMethodBehavior,
    this._nativeFieldLoadBehavior,
    this._nativeFieldStoreBehavior,
    this.interopNullChecks,
  );

  factory NativeData.fromIr(KernelToElementMap map, IrAnnotationData data) {
    NativeBasicData nativeBasicData = NativeBasicData.fromIr(map, data);
    Map<MemberEntity, String> nativeMemberName = {};
    Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = {};
    Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = {};
    Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = {};

    data.forEachNativeMethodData((
      ir.Member node,
      String name,
      Iterable<String> createsAnnotations,
      Iterable<String> returnsAnnotations,
    ) {
      final member = map.getMember(node) as FunctionEntity;
      nativeMemberName[member] = name;
      bool isJsInterop = nativeBasicData.isJsInteropMember(member);
      nativeMethodBehavior[member] = map.getNativeBehaviorForMethod(
        node,
        createsAnnotations,
        returnsAnnotations,
        isJsInterop: isJsInterop,
      );
    });

    data.forEachNativeFieldData((
      ir.Member node,
      String name,
      Iterable<String> createsAnnotations,
      Iterable<String> returnsAnnotations,
    ) {
      final field = map.getMember(node) as FieldEntity;
      nativeMemberName[field] = name;
      bool isJsInterop = nativeBasicData.isJsInteropMember(field);
      node as ir.Field;
      nativeFieldLoadBehavior[field] = map.getNativeBehaviorForFieldLoad(
        node,
        createsAnnotations,
        returnsAnnotations,
        isJsInterop: isJsInterop,
      );
      nativeFieldStoreBehavior[field] = map.getNativeBehaviorForFieldStore(
        node,
      );
    });

    return NativeData(
      nativeBasicData,
      nativeMemberName,
      nativeMethodBehavior,
      nativeFieldLoadBehavior,
      nativeFieldStoreBehavior,
      const {},
    );
  }

  /// Deserializes a [NativeData] object from [source].
  factory NativeData.readFromDataSource(
    DataSourceReader source,
    ElementEnvironment elementEnvironment,
  ) {
    source.begin(tag);
    NativeBasicData nativeBasicData = NativeBasicData.readFromDataSource(
      source,
      elementEnvironment,
    );
    Map<MemberEntity, String> nativeMemberName = source.readMemberMap(
      (MemberEntity member) => source.readString(),
    );
    Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = source
        .readMemberMap(
          (MemberEntity member) => NativeBehavior.readFromDataSource(source),
        );
    Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = source
        .readMemberMap(
          (MemberEntity member) => NativeBehavior.readFromDataSource(source),
        );
    Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = source
        .readMemberMap(
          (MemberEntity member) => NativeBehavior.readFromDataSource(source),
        );
    Map<Selector, InteropNullCheckKind> interopNullChecks = source
        .readSelectorMap((_) => source.readEnum(InteropNullCheckKind.values));
    source.end(tag);
    return NativeData(
      nativeBasicData,
      nativeMemberName,
      nativeMethodBehavior,
      nativeFieldLoadBehavior,
      nativeFieldStoreBehavior,
      interopNullChecks,
    );
  }

  /// Serializes this [NativeData] to [sink].
  @override
  void writeToDataSink(DataSinkWriter sink) {
    sink.begin(tag);
    _nativeBasicData.writeToDataSink(sink);

    sink.writeMemberMap(
      _nativeMemberName,
      (MemberEntity member, String name) => sink.writeString(name),
    );

    sink.writeMemberMap(_nativeMethodBehavior, (
      MemberEntity member,
      NativeBehavior behavior,
    ) {
      behavior.writeToDataSink(sink);
    });

    sink.writeMemberMap(_nativeFieldLoadBehavior, (
      MemberEntity member,
      NativeBehavior behavior,
    ) {
      behavior.writeToDataSink(sink);
    });
    sink.writeMemberMap(_nativeFieldStoreBehavior, (
      MemberEntity member,
      NativeBehavior behavior,
    ) {
      behavior.writeToDataSink(sink);
    });

    sink.writeSelectorMap(
      interopNullChecks,
      sink.writeEnum<InteropNullCheckKind>,
    );

    sink.end(tag);
  }

  @override
  bool get _isAllowInteropUsed => _nativeBasicData._isAllowInteropUsed;

  @override
  set _isAllowInteropUsed(bool value) =>
      _nativeBasicData._isAllowInteropUsed = value;

  @override
  bool get isAllowInteropUsed => _nativeBasicData.isAllowInteropUsed;

  @override
  void registerAllowInterop() => _nativeBasicData.registerAllowInterop();

  @override
  Map<LibraryEntity, String> get _jsInteropLibraries =>
      _nativeBasicData._jsInteropLibraries;

  @override
  Set<ClassEntity> get _anonymousJsInteropClasses =>
      _nativeBasicData._anonymousJsInteropClasses;

  @override
  Set<ClassEntity> get _staticInteropClasses =>
      _nativeBasicData._staticInteropClasses;

  @override
  Map<ClassEntity, String> get _jsInteropClasses =>
      _nativeBasicData._jsInteropClasses;

  @override
  Map<MemberEntity, String?> get _jsInteropMembers =>
      _nativeBasicData._jsInteropMembers;

  /// Returns `true` if [element] has an `@Anonymous` annotation.
  bool isAnonymousJsInteropClass(ClassEntity element) {
    return _anonymousJsInteropClasses.contains(element);
  }

  /// Returns `true` if [element] has an `@staticInterop` annotation.
  bool isStaticInteropClass(ClassEntity element) {
    return _staticInteropClasses.contains(element);
  }

  @override
  bool isNativeClass(ClassEntity element) =>
      _nativeBasicData.isNativeClass(element);

  @override
  List<String> getNativeTagsOfClass(ClassEntity cls) =>
      _nativeBasicData.getNativeTagsOfClass(cls);

  @override
  bool hasNativeTagsForcedNonLeaf(ClassEntity cls) =>
      _nativeBasicData.hasNativeTagsForcedNonLeaf(cls);

  @override
  bool get isJsInteropUsed => _nativeBasicData.isJsInteropUsed;

  @override
  bool isJsInteropLibrary(LibraryEntity element) =>
      _nativeBasicData.isJsInteropLibrary(element);

  @override
  bool isJsInteropClass(ClassEntity element) =>
      _nativeBasicData.isJsInteropClass(element);

  @override
  bool isNativeOrExtendsNative(ClassEntity? element) =>
      _nativeBasicData.isNativeOrExtendsNative(element);

  /// Returns the explicit js interop name for library [element].
  String? getJsInteropLibraryName(LibraryEntity element) {
    return _jsInteropLibraries[element];
  }

  /// Returns the explicit js interop name for class [element].
  String? getJsInteropClassName(ClassEntity element) {
    return _jsInteropClasses[element];
  }

  /// Returns the explicit js interop name for member [element].
  String? getJsInteropMemberName(MemberEntity element) {
    return _jsInteropMembers[element];
  }

  @override
  bool _isJsInteropMember(MemberEntity element) {
    return _jsInteropMembers.containsKey(element);
  }

  @override
  bool isJsInteropMember(MemberEntity element) {
    if (element.isFunction ||
        element is ConstructorEntity ||
        element.isGetter ||
        element.isSetter) {
      final function = element as FunctionEntity;
      if (!function.isExternal) return false;

      if (_isJsInteropMember(function)) return true;
      if (function.enclosingClass != null) {
        return isJsInteropClass(function.enclosingClass!);
      }
      if (function.isTopLevel) {
        return isJsInteropLibrary(function.library);
      }
      return false;
    } else {
      return _isJsInteropMember(element);
    }
  }

  /// Returns `true` if the name of [element] is fixed for the generated
  /// JavaScript.
  bool hasFixedBackendName(MemberEntity element) {
    return isJsInteropMember(element) || _nativeMemberName.containsKey(element);
  }

  /// Computes the name for [element] to use in the generated JavaScript. This
  /// is either given through a native annotation or a js interop annotation.
  String? getFixedBackendName(MemberEntity element) {
    String? name = _nativeMemberName[element];
    if (name == null && isJsInteropMember(element)) {
      if (element is ConstructorEntity) {
        name = _jsClassNameHelper(element.enclosingClass);
      } else {
        name = _jsMemberNameHelper(element);
        // Top-level static JS interop members can be associated with a dotted
        // name, if so, fixedBackendName is the last segment.
        if (element.isTopLevel && name.contains('.')) {
          name = name.substring(name.lastIndexOf('.') + 1);
        }
      }
      _nativeMemberName[element] = name;
    }
    return name;
  }

  String _jsLibraryNameHelper(LibraryEntity element) {
    String? jsInteropName = getJsInteropLibraryName(element);
    if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
    return 'self';
  }

  String _jsClassNameHelper(ClassEntity element) {
    String? jsInteropName = getJsInteropClassName(element);
    if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
    return computeUnescapedJSInteropName(element.name);
  }

  String _jsMemberNameHelper(MemberEntity element) {
    String? jsInteropName = _jsInteropMembers[element];
    assert(
      !(_jsInteropMembers.containsKey(element) && jsInteropName == null),
      failedAt(
        element,
        'Member $element is js interop but js interop name has not yet '
        'been computed.',
      ),
    );
    if (jsInteropName != null && jsInteropName.isNotEmpty) {
      return jsInteropName;
    }
    return computeUnescapedJSInteropName(element.name!);
  }

  /// Returns a JavaScript path specifying the context in which
  /// [element.fixedBackendName] should be evaluated. Only applicable for
  /// elements using typed JavaScript interop.
  /// For example: fixedBackendPath for the static method createMap in the
  /// Map class of the goog.map JavaScript library would have path
  /// "goog.maps.Map".
  String? getFixedBackendMethodPath(FunctionEntity element) {
    if (!isJsInteropMember(element)) return null;
    if (element.isInstanceMember) return 'this';
    if (element is ConstructorEntity) {
      return _fixedBackendClassPath(element.enclosingClass);
    }
    StringBuffer sb = StringBuffer();
    sb.write(_jsLibraryNameHelper(element.library));
    if (element.enclosingClass != null) {
      sb
        ..write('.')
        ..write(_jsClassNameHelper(element.enclosingClass!));
    }

    // Top-level static JS interop members can be associated with a dotted
    // name, if so, fixedBackendPath includes all but the last segment.
    final name = _jsMemberNameHelper(element);
    if (element.isTopLevel && name.contains('.')) {
      sb
        ..write('.')
        ..write(name.substring(0, name.lastIndexOf('.')));
    }
    return sb.toString();
  }

  String? _fixedBackendClassPath(ClassEntity element) {
    if (!isJsInteropClass(element)) return null;
    return _jsLibraryNameHelper(element.library);
  }

  /// Returns `true` if [element] corresponds to a native JavaScript member.
  ///
  /// A member is marked as native either through the native mechanism
  /// (`@Native(...)` or the `native` pseudo keyword) allowed for internal
  /// libraries or via the typed JavaScriptInterop mechanism allowed for user
  /// libraries.
  bool isNativeMember(MemberEntity element) {
    if (isJsInteropMember(element)) return true;
    return _nativeMemberName.containsKey(element);
  }

  /// Returns the [NativeBehavior] for calling the native [method].
  NativeBehavior getNativeMethodBehavior(FunctionEntity method) {
    assert(
      _nativeMethodBehavior.containsKey(method),
      failedAt(
        method,
        "No native method behavior has been computed for $method.",
      ),
    );
    return _nativeMethodBehavior[method]!;
  }

  /// Returns the [NativeBehavior] for reading from the native [field].
  NativeBehavior getNativeFieldLoadBehavior(FieldEntity field) {
    assert(
      _nativeFieldLoadBehavior.containsKey(field),
      failedAt(
        field,
        "No native field load behavior has been "
        "computed for $field.",
      ),
    );
    return _nativeFieldLoadBehavior[field]!;
  }

  /// Returns the [NativeBehavior] for writing to the native [field].
  NativeBehavior getNativeFieldStoreBehavior(FieldEntity field) {
    assert(
      _nativeFieldStoreBehavior.containsKey(field),
      failedAt(
        field,
        "No native field store behavior has been computed for $field.",
      ),
    );
    return _nativeFieldStoreBehavior[field]!;
  }

  /// Apply JS$ escaping scheme to convert possible escaped Dart names into
  /// JS names.
  String computeUnescapedJSInteropName(String name) {
    return name.startsWith(_jsInteropEscapePrefix)
        ? name.substring(_jsInteropEscapePrefix.length)
        : name;
  }

  @override
  Map<ClassEntity, NativeClassTag> get _nativeClassTagInfo =>
      _nativeBasicData._nativeClassTagInfo;

  @override
  ElementEnvironment get _env => _nativeBasicData._env;

  @override
  NativeData convert(JsToFrontendMap map, ElementEnvironment environment) {
    NativeBasicData nativeBasicData = _nativeBasicData.convert(
      map,
      environment,
    );
    Map<MemberEntity, String> nativeMemberName = map.toBackendMemberMap(
      _nativeMemberName,
      identity,
    );
    final nativeMethodBehavior = <FunctionEntity, NativeBehavior>{};
    _nativeMethodBehavior.forEach((
      FunctionEntity method,
      NativeBehavior behavior,
    ) {
      final backendMethod = map.toBackendMember(method) as FunctionEntity?;
      if (backendMethod != null) {
        // If [method] isn't used it doesn't have a corresponding backend
        // method.
        nativeMethodBehavior[backendMethod] = behavior.convert(map);
      }
    });
    NativeBehavior convertNativeBehavior(NativeBehavior behavior) =>
        behavior.convert(map);
    Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = map
        .toBackendMemberMap(_nativeFieldLoadBehavior, convertNativeBehavior);
    Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = map
        .toBackendMemberMap(_nativeFieldStoreBehavior, convertNativeBehavior);
    return NativeData(
      nativeBasicData,
      nativeMemberName,
      nativeMethodBehavior,
      nativeFieldLoadBehavior,
      nativeFieldStoreBehavior,
      interopNullChecks,
    );
  }
}

class NativeClassTag {
  final List<String> names;
  final bool isNonLeaf;

  factory NativeClassTag(String tagText) {
    List<String> tags = tagText.split(',');
    List<String> names = tags
        .where((s) => s.isNotEmpty && !s.startsWith('!'))
        .toList();
    bool isNonLeaf = tags.contains('!nonleaf');
    return NativeClassTag.internal(names, isNonLeaf);
  }

  NativeClassTag.internal(this.names, this.isNonLeaf);

  String get text {
    StringBuffer sb = StringBuffer();
    sb.write(names.join(','));
    if (isNonLeaf) {
      if (names.isNotEmpty) {
        sb.write(',');
      }
      sb.write('!nonleaf');
    }
    return sb.toString();
  }

  @override
  int get hashCode => Hashing.listHash(names, isNonLeaf.hashCode);

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! NativeClassTag) return false;
    return equalElements(names, other.names) && isNonLeaf == other.isNonLeaf;
  }

  @override
  String toString() => text;
}
