// Copyright (c) 2019, 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/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/extensions.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_system.dart';

/// Failure because of there is no most specific signature in [candidates].
class CandidatesConflict extends Conflict {
  /// The list has at least two items, because the only item is always valid.
  final List<ExecutableElement> candidates;

  CandidatesConflict({
    required Name name,
    required this.candidates,
  }) : super(name);
}

/// Failure to find a valid signature from superinterfaces.
class Conflict {
  /// The name for which we failed to find a valid signature.
  final Name name;

  Conflict(this.name);
}

/// Failure because of a getter and a method from direct superinterfaces.
class GetterMethodConflict extends Conflict {
  final ExecutableElement getter;
  final ExecutableElement method;

  GetterMethodConflict({
    required Name name,
    required this.getter,
    required this.method,
  }) : super(name);
}

/// Manages knowledge about interface types and their members.
class InheritanceManager3 {
  static final _noSuchMethodName =
      Name(null, FunctionElement.NO_SUCH_METHOD_METHOD_NAME);

  /// Cached instance interfaces for [ClassElement].
  final Map<ClassElement, Interface> _interfaces = {};

  /// The set of classes that are currently being processed, used to detect
  /// self-referencing cycles.
  final Set<ClassElement> _processingClasses = <ClassElement>{};

  /// Combine [candidates] into a single signature in the [targetClass].
  ///
  /// If such signature does not exist, return `null`, and if [conflicts] is
  /// not `null`, add a new [Conflict] to it.
  ExecutableElement? combineSignatures({
    required ClassElement targetClass,
    required List<ExecutableElement> candidates,
    required bool doTopMerge,
    required Name name,
    List<Conflict>? conflicts,
  }) {
    // If just one candidate, it is always valid.
    if (candidates.length == 1) {
      return candidates[0];
    }

    // Check for a getter/method conflict.
    var conflict = _checkForGetterMethodConflict(name, candidates);
    if (conflict != null) {
      conflicts?.add(conflict);
      return null;
    }

    var targetLibrary = targetClass.library as LibraryElementImpl;
    var typeSystem = targetLibrary.typeSystem;

    var validOverrides = <ExecutableElement>[];
    for (var i = 0; i < candidates.length; i++) {
      ExecutableElement? validOverride = candidates[i];
      var validOverrideType = validOverride.type;
      for (var j = 0; j < candidates.length; j++) {
        var candidate = candidates[j];
        if (!typeSystem.isSubtypeOf(validOverrideType, candidate.type)) {
          validOverride = null;
          break;
        }
      }
      if (validOverride != null) {
        validOverrides.add(validOverride);
      }
    }

    if (validOverrides.isEmpty) {
      conflicts?.add(
        CandidatesConflict(
          name: name,
          candidates: candidates,
        ),
      );
      return null;
    }

    if (doTopMerge) {
      var typeSystem = targetClass.library.typeSystem as TypeSystemImpl;
      return _topMerge(typeSystem, targetClass, validOverrides);
    } else {
      return validOverrides.first;
    }
  }

  /// Return the result of [getInherited2] with [type] substitution.
  ExecutableElement? getInherited(InterfaceType type, Name name) {
    var rawElement = getInherited2(type.element, name);
    if (rawElement == null) {
      return null;
    }

    return ExecutableMember.from2(
      rawElement,
      Substitution.fromInterfaceType(type),
    );
  }

  /// Return the most specific signature of the member with the given [name]
  /// that [element] inherits from the mixins, superclasses, or interfaces;
  /// or `null` if no member is inherited because the member is not declared
  /// at all, or because there is no the most specific signature.
  ///
  /// This is equivalent to `getInheritedMap2(type)[name]`.
  ExecutableElement? getInherited2(ClassElement element, Name name) {
    return getInheritedMap2(element)[name];
  }

  /// Return signatures of all concrete members that the given [type] inherits
  /// from the superclasses and mixins.
  @Deprecated('Use getInheritedConcreteMap2')
  Map<Name, ExecutableElement> getInheritedConcreteMap(InterfaceType type) {
    var result = <Name, ExecutableElement>{};

    var substitution = Substitution.fromInterfaceType(type);
    var rawMap = getInheritedConcreteMap2(type.element);
    for (var rawEntry in rawMap.entries) {
      result[rawEntry.key] = ExecutableMember.from2(
        rawEntry.value,
        substitution,
      );
    }

    return result;
  }

  /// Return signatures of all concrete members that the given [element] inherits
  /// from the superclasses and mixins.
  Map<Name, ExecutableElement> getInheritedConcreteMap2(ClassElement element) {
    var interface = getInterface(element);
    return interface._superImplemented.last;
  }

  /// Return the mapping from names to most specific signatures of members
  /// inherited from the super-interfaces (superclasses, mixins, and
  /// interfaces).  If there is no most specific signature for a name, the
  /// corresponding name will not be included.
  @Deprecated('Use getInheritedMap2')
  Map<Name, ExecutableElement> getInheritedMap(InterfaceType type) {
    var result = <Name, ExecutableElement>{};

    var substitution = Substitution.fromInterfaceType(type);
    var rawMap = getInheritedMap2(type.element);
    for (var rawEntry in rawMap.entries) {
      result[rawEntry.key] = ExecutableMember.from2(
        rawEntry.value,
        substitution,
      );
    }

    return result;
  }

  /// Return the mapping from names to most specific signatures of members
  /// inherited from the super-interfaces (superclasses, mixins, and
  /// interfaces).  If there is no most specific signature for a name, the
  /// corresponding name will not be included.
  Map<Name, ExecutableElement> getInheritedMap2(ClassElement element) {
    var interface = getInterface(element);
    var inheritedMap = interface._inheritedMap;
    if (inheritedMap == null) {
      inheritedMap = interface._inheritedMap = {};
      _findMostSpecificFromNamedCandidates(
        element,
        inheritedMap,
        interface._overridden,
        doTopMerge: false,
      );
    }
    return inheritedMap;
  }

  /// Return the interface of the given [element].  It might include
  /// private members, not necessary accessible in all libraries.
  Interface getInterface(ClassElement element) {
    var result = _interfaces[element];
    if (result != null) {
      return result;
    }
    _interfaces[element] = Interface._empty;

    if (!_processingClasses.add(element)) {
      return Interface._empty;
    }

    try {
      if (element.isMixin) {
        result = _getInterfaceMixin(element);
      } else {
        result = _getInterfaceClass(element);
      }
    } finally {
      _processingClasses.remove(element);
    }

    _interfaces[element] = result;
    return result;
  }

  /// Return the result of [getMember2] with [type] substitution.
  ExecutableElement? getMember(
    InterfaceType type,
    Name name, {
    bool concrete = false,
    int forMixinIndex = -1,
    bool forSuper = false,
  }) {
    var rawElement = getMember2(
      type.element,
      name,
      concrete: concrete,
      forMixinIndex: forMixinIndex,
      forSuper: forSuper,
    );
    if (rawElement == null) {
      return null;
    }

    var substitution = Substitution.fromInterfaceType(type);
    return ExecutableMember.from2(rawElement, substitution);
  }

  /// Return the member with the given [name].
  ///
  /// If [concrete] is `true`, the concrete implementation is returned,
  /// from the given [element], or its superclass.
  ///
  /// If [forSuper] is `true`, then [concrete] is implied, and only concrete
  /// members from the superclass are considered.
  ///
  /// If [forMixinIndex] is specified, only the nominal superclass, and the
  /// given number of mixins after it are considered.  For example for `1` in
  /// `class C extends S with M1, M2, M3`, only `S` and `M1` are considered.
  ExecutableElement? getMember2(
    ClassElement element,
    Name name, {
    bool concrete = false,
    int forMixinIndex = -1,
    bool forSuper = false,
  }) {
    var interface = getInterface(element);
    if (forSuper) {
      var superImplemented = interface._superImplemented;
      if (forMixinIndex >= 0) {
        return superImplemented[forMixinIndex][name];
      }
      if (superImplemented.isNotEmpty) {
        return superImplemented.last[name];
      } else {
        assert(element.name == 'Object');
        return null;
      }
    }
    if (concrete) {
      return interface.implemented[name];
    }
    return interface.map[name];
  }

  /// Return all members of mixins, superclasses, and interfaces that a member
  /// with the given [name], defined in the [type], would override; or `null`
  /// if no members would be overridden.
  @Deprecated('Use getOverridden2')
  List<ExecutableElement>? getOverridden(InterfaceType type, Name name) {
    return getOverridden2(type.element, name);
  }

  /// Return all members of mixins, superclasses, and interfaces that a member
  /// with the given [name], defined in the [element], would override; or `null`
  /// if no members would be overridden.
  List<ExecutableElement>? getOverridden2(ClassElement element, Name name) {
    var interface = getInterface(element);
    return interface._overridden[name];
  }

  /// Remove interfaces for classes defined in specified libraries.
  void removeOfLibraries(Set<String> uriStrSet) {
    _interfaces.removeWhere((element, _) {
      var uriStr = '${element.librarySource.uri}';
      return uriStrSet.contains(uriStr);
    });
  }

  void _addCandidates({
    required Map<Name, List<ExecutableElement>> namedCandidates,
    required MapSubstitution substitution,
    required Interface interface,
    required bool isNonNullableByDefault,
  }) {
    var map = interface.map;
    for (var entry in map.entries) {
      var name = entry.key;
      var candidate = entry.value;

      candidate = ExecutableMember.from2(candidate, substitution);

      if (!isNonNullableByDefault) {
        candidate = Member.legacy(candidate) as ExecutableElement;
      }

      var candidates = namedCandidates[name];
      if (candidates == null) {
        candidates = <ExecutableElement>[];
        namedCandidates[name] = candidates;
      }

      candidates.add(candidate);
    }
  }

  void _addImplemented(
    Map<Name, ExecutableElement> implemented,
    ClassElement element,
  ) {
    var libraryUri = element.librarySource.uri;

    void addMember(ExecutableElement member) {
      if (!member.isAbstract && !member.isStatic) {
        var name = Name(libraryUri, member.name);
        implemented[name] = member;
      }
    }

    element.methods.forEach(addMember);
    element.accessors.forEach(addMember);
  }

  void _addMixinMembers({
    required Map<Name, ExecutableElement> implemented,
    required MapSubstitution substitution,
    required Interface mixin,
    required bool isNonNullableByDefault,
  }) {
    for (var entry in mixin.implemented.entries) {
      var executable = entry.value;
      if (executable.isAbstract) {
        continue;
      }

      var class_ = executable.enclosingElement;
      if (class_ is ClassElement && class_.isDartCoreObject) {
        continue;
      }

      executable = ExecutableMember.from2(executable, substitution);

      if (!isNonNullableByDefault) {
        executable = Member.legacy(executable) as ExecutableElement;
      }

      implemented[entry.key] = executable;
    }
  }

  /// Check that all [candidates] for the given [name] have the same kind, all
  /// getters, all methods, or all setter.  If a conflict found, return the
  /// new [Conflict] instance that describes it.
  Conflict? _checkForGetterMethodConflict(
      Name name, List<ExecutableElement> candidates) {
    assert(candidates.length > 1);

    ExecutableElement? getter;
    ExecutableElement? method;
    for (var candidate in candidates) {
      var kind = candidate.kind;
      if (kind == ElementKind.GETTER) {
        getter ??= candidate;
      }
      if (kind == ElementKind.METHOD) {
        method ??= candidate;
      }
    }

    if (getter == null || method == null) {
      return null;
    } else {
      return GetterMethodConflict(name: name, getter: getter, method: method);
    }
  }

  /// The given [namedCandidates] maps names to candidates from direct
  /// superinterfaces.  Find the most specific signature, and put it into the
  /// [map], if there is no one yet (from the class itself).  If there is no
  /// such single most specific signature (i.e. no valid override), then add a
  /// new conflict description.
  List<Conflict> _findMostSpecificFromNamedCandidates(
    ClassElement targetClass,
    Map<Name, ExecutableElement> map,
    Map<Name, List<ExecutableElement>> namedCandidates, {
    required bool doTopMerge,
  }) {
    var conflicts = <Conflict>[];

    for (var entry in namedCandidates.entries) {
      var name = entry.key;
      if (map.containsKey(name)) {
        continue;
      }

      var candidates = entry.value;

      var combinedSignature = combineSignatures(
        targetClass: targetClass,
        candidates: candidates,
        doTopMerge: doTopMerge,
        name: name,
        conflicts: conflicts,
      );

      if (combinedSignature != null) {
        map[name] = combinedSignature;
        continue;
      }
    }

    return conflicts;
  }

  Interface _getInterfaceClass(ClassElement element) {
    var classLibrary = element.library;
    var isNonNullableByDefault = classLibrary.isNonNullableByDefault;

    var namedCandidates = <Name, List<ExecutableElement>>{};
    var superImplemented = <Map<Name, ExecutableElement>>[];
    var implemented = <Name, ExecutableElement>{};

    Interface? superTypeInterface;
    var superType = element.supertype;
    if (superType != null) {
      var substitution = Substitution.fromInterfaceType(superType);
      superTypeInterface = getInterface(superType.element);
      _addCandidates(
        namedCandidates: namedCandidates,
        substitution: substitution,
        interface: superTypeInterface,
        isNonNullableByDefault: isNonNullableByDefault,
      );

      for (var entry in superTypeInterface.implemented.entries) {
        var executable = entry.value;
        executable = ExecutableMember.from2(executable, substitution);
        if (!isNonNullableByDefault) {
          executable = Member.legacy(executable) as ExecutableElement;
        }
        implemented[entry.key] = executable;
      }

      superImplemented.add(implemented);
    }

    // TODO(scheglov) Handling of members for super and mixins is not
    // optimal. We always have just one member for each name in super,
    // multiple candidates happen only when we merge super and multiple
    // interfaces. Consider using `Map<Name, ExecutableElement>` here.
    var mixinsConflicts = <List<Conflict>>[];
    for (var mixin in element.mixins) {
      var mixinElement = mixin.element;
      var substitution = Substitution.fromInterfaceType(mixin);
      var mixinInterface = getInterface(mixinElement);
      // `class X extends S with M1, M2 {}` is semantically a sequence of:
      //     class S&M1 extends S implements M1 {
      //       // declared M1 members
      //     }
      //     class S&M2 extends S&M1 implements M2 {
      //       // declared M2 members
      //     }
      //     class X extends S&M2 {
      //       // declared X members
      //     }
      // So, each mixin always replaces members in the interface.
      // And there are individual override conflicts for each mixin.
      var candidatesFromSuperAndMixin = <Name, List<ExecutableElement>>{};
      var mixinConflicts = <Conflict>[];
      for (var entry in mixinInterface.map.entries) {
        var name = entry.key;
        var candidate = ExecutableMember.from2(
          entry.value,
          substitution,
        );

        var currentList = namedCandidates[name];
        if (currentList == null) {
          namedCandidates[name] = [
            isNonNullableByDefault
                ? candidate
                : Member.legacy(candidate) as ExecutableElement,
          ];
          continue;
        }

        var current = currentList.single;
        if (candidate.enclosingElement == mixinElement) {
          namedCandidates[name] = [
            isNonNullableByDefault
                ? candidate
                : Member.legacy(candidate) as ExecutableElement,
          ];
          if (current.kind != candidate.kind) {
            var currentIsGetter = current.kind == ElementKind.GETTER;
            mixinConflicts.add(
              GetterMethodConflict(
                name: name,
                getter: currentIsGetter ? current : candidate,
                method: currentIsGetter ? candidate : current,
              ),
            );
          }
        } else {
          candidatesFromSuperAndMixin[name] = [current, candidate];
        }
      }

      // Merge members from the superclass and the mixin interface.
      {
        var map = <Name, ExecutableElement>{};
        _findMostSpecificFromNamedCandidates(
          element,
          map,
          candidatesFromSuperAndMixin,
          doTopMerge: true,
        );
        for (var entry in map.entries) {
          namedCandidates[entry.key] = [
            isNonNullableByDefault
                ? entry.value
                : Member.legacy(entry.value) as ExecutableElement,
          ];
        }
      }

      mixinsConflicts.add(mixinConflicts);

      implemented = Map.of(implemented);
      _addMixinMembers(
        implemented: implemented,
        substitution: substitution,
        mixin: mixinInterface,
        isNonNullableByDefault: isNonNullableByDefault,
      );

      superImplemented.add(implemented);
    }

    for (var interface in element.interfaces) {
      _addCandidates(
        namedCandidates: namedCandidates,
        substitution: Substitution.fromInterfaceType(interface),
        interface: getInterface(interface.element),
        isNonNullableByDefault: isNonNullableByDefault,
      );
    }

    implemented = Map.of(implemented);
    _addImplemented(implemented, element);

    // If a class declaration has a member declaration, the signature of that
    // member declaration becomes the signature in the interface.
    var declared = _getTypeMembers(element);

    // If a class declaration does not have a member declaration with a
    // particular name, but some super-interfaces do have a member with that
    // name, it's a compile-time error if there is no signature among the
    // super-interfaces that is a valid override of all the other
    // super-interface signatures with the same name. That "most specific"
    // signature becomes the signature of the class's interface.
    var interface = Map.of(declared);
    List<Conflict> conflicts = _findMostSpecificFromNamedCandidates(
      element,
      interface,
      namedCandidates,
      doTopMerge: true,
    );

    var noSuchMethodForwarders = <Name>{};
    if (element.isAbstract) {
      if (superTypeInterface != null) {
        noSuchMethodForwarders = superTypeInterface._noSuchMethodForwarders;
      }
    } else {
      var noSuchMethod = implemented[_noSuchMethodName];
      if (noSuchMethod != null && !_isDeclaredInObject(noSuchMethod)) {
        var superForwarders = superTypeInterface?._noSuchMethodForwarders;
        for (var entry in interface.entries) {
          var name = entry.key;
          if (!implemented.containsKey(name) ||
              superForwarders != null && superForwarders.contains(name)) {
            implemented[name] = entry.value;
            noSuchMethodForwarders.add(name);
          }
        }
      }
    }

    /// TODO(scheglov) Instead of merging conflicts we could report them on
    /// the corresponding mixins applied in the class.
    for (var mixinConflicts in mixinsConflicts) {
      if (mixinConflicts.isNotEmpty) {
        conflicts.addAll(mixinConflicts);
      }
    }

    implemented = implemented.map<Name, ExecutableElement>((key, value) {
      var result = _inheritCovariance(element, namedCandidates, key, value);
      return MapEntry(key, result);
    });

    return Interface._(
      interface,
      declared,
      implemented,
      noSuchMethodForwarders,
      namedCandidates,
      superImplemented,
      conflicts,
    );
  }

  Interface _getInterfaceMixin(ClassElement element) {
    var classLibrary = element.library;
    var isNonNullableByDefault = classLibrary.isNonNullableByDefault;

    var superCandidates = <Name, List<ExecutableElement>>{};
    for (var constraint in element.superclassConstraints) {
      var substitution = Substitution.fromInterfaceType(constraint);
      var interfaceObj = getInterface(constraint.element);
      _addCandidates(
        namedCandidates: superCandidates,
        substitution: substitution,
        interface: interfaceObj,
        isNonNullableByDefault: isNonNullableByDefault,
      );
    }

    // `mixin M on S1, S2 {}` can call using `super` any instance member
    // from its superclass constraints, whether it is abstract or concrete.
    var superInterface = <Name, ExecutableElement>{};
    var superConflicts = _findMostSpecificFromNamedCandidates(
      element,
      superInterface,
      superCandidates,
      doTopMerge: true,
    );

    var interfaceCandidates = Map.of(superCandidates);
    for (var interface in element.interfaces) {
      _addCandidates(
        namedCandidates: interfaceCandidates,
        substitution: Substitution.fromInterfaceType(interface),
        interface: getInterface(interface.element),
        isNonNullableByDefault: isNonNullableByDefault,
      );
    }

    var declared = _getTypeMembers(element);

    var interface = Map.of(declared);
    var interfaceConflicts = _findMostSpecificFromNamedCandidates(
      element,
      interface,
      interfaceCandidates,
      doTopMerge: true,
    );

    var implemented = <Name, ExecutableElement>{};
    _addImplemented(implemented, element);

    return Interface._(
      interface,
      declared,
      implemented,
      {},
      interfaceCandidates,
      [superInterface],
      <Conflict>[...superConflicts, ...interfaceConflicts],
    );
  }

  /// If a candidate from [namedCandidates] has covariant parameters, return
  /// a copy of the [executable] with the corresponding parameters marked
  /// covariant. If there are no covariant parameters, or parameters to
  /// update are already covariant, return the [executable] itself.
  ExecutableElement _inheritCovariance(
    ClassElement class_,
    Map<Name, List<ExecutableElement>> namedCandidates,
    Name name,
    ExecutableElement executable,
  ) {
    if (executable.enclosingElement == class_) {
      return executable;
    }

    var parameters = executable.parameters;
    if (parameters.isEmpty) {
      return executable;
    }

    var candidates = namedCandidates[name];
    if (candidates == null) {
      return executable;
    }

    // Find parameters that are covariant (by declaration) in any overridden.
    Set<_ParameterDesc>? covariantParameters;
    for (var candidate in candidates) {
      var parameters = candidate.parameters;
      for (var i = 0; i < parameters.length; i++) {
        var parameter = parameters[i];
        if (parameter.isCovariant) {
          covariantParameters ??= {};
          covariantParameters.add(
            _ParameterDesc(i, parameter),
          );
        }
      }
    }

    if (covariantParameters == null) {
      return executable;
    }

    // Update covariance of the parameters of the chosen executable.
    List<ParameterElement>? transformedParameters;
    for (var index = 0; index < parameters.length; index++) {
      var parameter = parameters[index];
      var shouldBeCovariant = covariantParameters.contains(
        _ParameterDesc(index, parameter),
      );
      if (parameter.isCovariant != shouldBeCovariant) {
        transformedParameters ??= parameters.toList();
        transformedParameters[index] = parameter.copyWith(
          isCovariant: shouldBeCovariant,
        );
      }
    }

    if (transformedParameters == null) {
      return executable;
    }

    if (executable is MethodElement) {
      var result = MethodElementImpl(executable.name, -1);
      result.enclosingElement = class_;
      result.isSynthetic = true;
      result.parameters = transformedParameters;
      result.prototype = executable;
      result.returnType = executable.returnType;
      result.typeParameters = executable.typeParameters;
      return result;
    }

    if (executable is PropertyAccessorElement) {
      assert(executable.isSetter);
      var result = PropertyAccessorElementImpl(executable.name, -1);
      result.enclosingElement = class_;
      result.isSynthetic = true;
      result.parameters = transformedParameters;
      result.prototype = executable;
      result.returnType = executable.returnType;

      var field = executable.variable;
      var resultField = FieldElementImpl(field.name, -1);
      resultField.enclosingElement = class_;
      resultField.getter = field.getter;
      resultField.setter = executable;
      resultField.type = executable.parameters[0].type;
      result.variable = resultField;

      return result;
    }

    return executable;
  }

  /// Given one or more [validOverrides], merge them into a single resulting
  /// signature. This signature always exists.
  ExecutableElement _topMerge(
    TypeSystemImpl typeSystem,
    ClassElement targetClass,
    List<ExecutableElement> validOverrides,
  ) {
    var first = validOverrides[0];

    if (validOverrides.length == 1) {
      return first;
    }

    if (!typeSystem.isNonNullableByDefault) {
      return first;
    }

    var firstType = first.type;
    var allTypesEqual = true;
    for (var executable in validOverrides) {
      if (executable.type != firstType) {
        allTypesEqual = false;
        break;
      }
    }

    if (allTypesEqual) {
      return first;
    }

    var resultType = validOverrides.map((e) {
      return typeSystem.normalize(e.type) as FunctionType;
    }).reduce((previous, next) {
      return typeSystem.topMerge(previous, next) as FunctionType;
    });

    for (var executable in validOverrides) {
      if (executable.type == resultType) {
        return executable;
      }
    }

    if (first is MethodElement) {
      var firstMethod = first;
      var result = MethodElementImpl(firstMethod.name, -1);
      result.enclosingElement = targetClass;
      result.typeParameters = resultType.typeFormals;
      result.returnType = resultType.returnType;
      result.parameters = resultType.parameters;
      return result;
    } else {
      var firstAccessor = first as PropertyAccessorElement;
      var variableName = firstAccessor.displayName;

      var result = PropertyAccessorElementImpl(variableName, -1);
      result.enclosingElement = targetClass;
      result.isGetter = firstAccessor.isGetter;
      result.isSetter = firstAccessor.isSetter;
      result.returnType = resultType.returnType;
      result.parameters = resultType.parameters;

      var field = FieldElementImpl(variableName, -1);
      if (firstAccessor.isGetter) {
        field.getter = result;
        field.type = result.returnType;
      } else {
        field.setter = result;
        field.type = result.parameters[0].type;
      }
      result.variable = field;

      return result;
    }
  }

  static Map<Name, ExecutableElement> _getTypeMembers(ClassElement element) {
    var declared = <Name, ExecutableElement>{};
    var libraryUri = element.librarySource.uri;

    var methods = element.methods;
    for (var i = 0; i < methods.length; i++) {
      var method = methods[i];
      if (!method.isStatic) {
        var name = Name(libraryUri, method.name);
        declared[name] = method;
      }
    }

    var accessors = element.accessors;
    for (var i = 0; i < accessors.length; i++) {
      var accessor = accessors[i];
      if (!accessor.isStatic) {
        var name = Name(libraryUri, accessor.name);
        declared[name] = accessor;
      }
    }

    return declared;
  }

  static bool _isDeclaredInObject(ExecutableElement element) {
    var enclosing = element.enclosingElement;
    return enclosing is ClassElement &&
        enclosing.supertype == null &&
        !enclosing.isMixin;
  }
}

/// The instance interface of an [InterfaceType].
class Interface {
  static final _empty = Interface._(
    const {},
    const {},
    const {},
    <Name>{},
    const {},
    const [{}],
    const [],
  );

  /// The map of names to their signature in the interface.
  final Map<Name, ExecutableElement> map;

  /// The map of declared names to their signatures.
  final Map<Name, ExecutableElement> declared;

  /// The map of names to their concrete implementations.
  final Map<Name, ExecutableElement> implemented;

  /// The set of names that are `noSuchMethod` forwarders in [implemented].
  final Set<Name> _noSuchMethodForwarders;

  /// The map of names to their signatures from the mixins, superclasses,
  /// or interfaces.
  final Map<Name, List<ExecutableElement>> _overridden;

  /// Each item of this list maps names to their concrete implementations.
  /// The first item of the list is the nominal superclass, next the nominal
  /// superclass plus the first mixin, etc. So, for the class like
  /// `class C extends S with M1, M2`, we get `[S, S&M1, S&M1&M2]`.
  final List<Map<Name, ExecutableElement>> _superImplemented;

  /// The list of conflicts between superinterfaces - the nominal superclass,
  /// mixins, and interfaces.  Does not include conflicts with the declared
  /// members of the class.
  final List<Conflict> conflicts;

  /// The map of names to the most specific signatures from the mixins,
  /// superclasses, or interfaces.
  Map<Name, ExecutableElement>? _inheritedMap;

  Interface._(
    this.map,
    this.declared,
    this.implemented,
    this._noSuchMethodForwarders,
    this._overridden,
    this._superImplemented,
    this.conflicts,
  );

  /// Return `true` if the [name] is implemented in the supertype.
  bool isSuperImplemented(Name name) {
    return _superImplemented.last.containsKey(name);
  }
}

/// A public name, or a private name qualified by a library URI.
class Name {
  /// If the name is private, the URI of the defining library.
  /// Otherwise, it is `null`.
  final Uri? libraryUri;

  /// The name of this name object.
  /// If the name starts with `_`, then the name is private.
  /// Names of setters end with `=`.
  final String name;

  /// Precomputed
  final bool isPublic;

  /// The cached, pre-computed hash code.
  @override
  final int hashCode;

  factory Name(Uri? libraryUri, String name) {
    if (name.startsWith('_')) {
      var hashCode = Object.hash(libraryUri, name);
      return Name._internal(libraryUri, name, false, hashCode);
    } else {
      return Name._internal(null, name, true, name.hashCode);
    }
  }

  Name._internal(this.libraryUri, this.name, this.isPublic, this.hashCode);

  @override
  bool operator ==(Object other) {
    return other is Name &&
        name == other.name &&
        libraryUri == other.libraryUri;
  }

  bool isAccessibleFor(Uri libraryUri) {
    return isPublic || this.libraryUri == libraryUri;
  }

  @override
  String toString() => libraryUri != null ? '$libraryUri::$name' : name;
}

class _ParameterDesc {
  final int? index;
  final String? name;

  factory _ParameterDesc(int index, ParameterElement element) {
    return element.isNamed
        ? _ParameterDesc.name(element.name)
        : _ParameterDesc.index(index);
  }

  _ParameterDesc.index(int index)
      : index = index,
        name = null;

  _ParameterDesc.name(String name)
      : index = null,
        name = name;

  @override
  int get hashCode {
    return index?.hashCode ?? name?.hashCode ?? 0;
  }

  @override
  bool operator ==(other) {
    return other is _ParameterDesc &&
        other.index == index &&
        other.name == name;
  }
}
