// Copyright (c) 2018, 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/generated/type_system.dart';
import 'package:analyzer/src/generated/utilities_general.dart';

/// Description of a failure to find a valid override from superinterfaces.
class Conflict {
  /// The name of an instance member for which we failed to find a valid
  /// override.
  final Name name;

  /// The list of candidates for a valid override for a member [name].  It has
  /// at least two items, because otherwise the only candidate is always valid.
  final List<FunctionType> candidates;

  /// The getter that conflicts with the [method], or `null`, if the conflict
  /// is inconsistent inheritance.
  final FunctionType getter;

  /// The method tha conflicts with the [getter], or `null`, if the conflict
  /// is inconsistent inheritance.
  final FunctionType method;

  Conflict(this.name, this.candidates, [this.getter, this.method]);
}

/// Manages knowledge about interface types and their members.
class InheritanceManager2 {
  final TypeSystem _typeSystem;

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

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

  /// Cached implemented members for [InterfaceType].
  final Map<InterfaceType, Map<Name, FunctionType>> _implemented = {};

  /// Cached member implemented in the mixin.
  final Map<InterfaceType, Map<Name, FunctionType>> _mixinMembers = {};

  InheritanceManager2(this._typeSystem);

  /// Return the member with the given [name] that the [type] inherits from the
  /// mixins, superclasses, or interfaces; or `null` if no member is inherited.
  FunctionType getInherited(InterfaceType type, Name name) {
    return getOverridden(type, name)?.last;
  }

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

    var result = _interfaces[type];
    if (result != null) {
      return result;
    }
    _interfaces[type] = Interface._empty;

    var classElement = type.element;
    if (!_processingClasses.add(classElement)) {
      return Interface._empty;
    }

    Map<Name, List<FunctionType>> namedCandidates = {};
    List<Map<Name, FunctionType>> superImplemented = [];
    Map<Name, FunctionType> declared;
    try {
      // If a class declaration has a member declaration, the signature of that
      // member declaration becomes the signature in the interface.
      declared = _getTypeMembers(type);

      for (var interface in type.interfaces) {
        _addCandidates(namedCandidates, interface);
      }

      if (type.element.isMixin) {
        for (var constraint in type.superclassConstraints) {
          _addCandidates(namedCandidates, constraint);
        }

        // `mixin M on S1, S2 {}` can call using `super` any instance member
        // from its superclass constraints, whether it is abstract or concrete.
        Map<Name, FunctionType> mixinSuperClass = {};
        _findMostSpecificFromNamedCandidates(mixinSuperClass, namedCandidates);
        superImplemented.add(mixinSuperClass);
      } else {
        Map<Name, FunctionType> implemented;

        if (type.superclass != null) {
          _addCandidates(namedCandidates, type.superclass);

          implemented = _getImplemented(type.superclass);
          superImplemented.add(implemented);
        }

        for (var mixin in type.mixins) {
          _addCandidates(namedCandidates, mixin);

          var implementedInMixin = _getImplemented(mixin);
          implemented = <Name, FunctionType>{}
            ..addAll(implemented)
            ..addAll(implementedInMixin);
          superImplemented.add(implemented);
        }
      }
    } finally {
      _processingClasses.remove(classElement);
    }

    // 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.
    Map<Name, FunctionType> map = new Map.of(declared);
    List<Conflict> conflicts = _findMostSpecificFromNamedCandidates(
      map,
      namedCandidates,
    );

    var interface = new Interface._(
      map,
      declared,
      namedCandidates,
      superImplemented,
      conflicts ?? const [],
    );
    _interfaces[type] = interface;
    return interface;
  }

  /// Return the member with the given [name].
  ///
  /// If [concrete] is `true`, the the concrete implementation is returned,
  /// from the given [type], 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.
  FunctionType getMember(
    InterfaceType type,
    Name name, {
    bool concrete: false,
    int forMixinIndex: -1,
    bool forSuper: false,
  }) {
    if (forSuper) {
      var superImplemented = getInterface(type)._superImplemented;
      if (forMixinIndex >= 0) {
        return superImplemented[forMixinIndex][name];
      }
      return superImplemented.last[name];
    }
    if (concrete) {
      return _getImplemented(type)[name];
    }
    return getInterface(type).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.
  List<FunctionType> getOverridden(InterfaceType type, Name name) {
    var interface = getInterface(type);
    return interface._overridden[name];
  }

  void _addCandidate(Map<Name, List<FunctionType>> namedCandidates, Name name,
      FunctionType candidate) {
    var candidates = namedCandidates[name];
    if (candidates == null) {
      candidates = <FunctionType>[];
      namedCandidates[name] = candidates;
    }

    candidates.add(candidate);
  }

  void _addCandidates(
      Map<Name, List<FunctionType>> namedCandidates, InterfaceType type) {
    var map = getInterface(type).map;
    for (var name in map.keys) {
      var candidate = map[name];
      _addCandidate(namedCandidates, name, candidate);
    }
  }

  /// 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<FunctionType> candidates) {
    assert(candidates.length > 1);

    bool allGetters = true;
    bool allMethods = true;
    bool allSetters = true;
    for (var candidate in candidates) {
      var kind = candidate.element.kind;
      if (kind != ElementKind.GETTER) {
        allGetters = false;
      }
      if (kind != ElementKind.METHOD) {
        allMethods = false;
      }
      if (kind != ElementKind.SETTER) {
        allSetters = false;
      }
    }

    if (allGetters || allMethods || allSetters) {
      return null;
    }

    FunctionType getterType;
    FunctionType methodType;
    for (var candidate in candidates) {
      var kind = candidate.element.kind;
      if (kind == ElementKind.GETTER) {
        getterType ??= candidate;
      }
      if (kind == ElementKind.METHOD) {
        methodType ??= candidate;
      }
    }
    return new Conflict(name, candidates, getterType, methodType);
  }

  /// 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(
      Map<Name, FunctionType> map,
      Map<Name, List<FunctionType>> namedCandidates) {
    List<Conflict> conflicts = null;

    for (var name in namedCandidates.keys) {
      if (map.containsKey(name)) {
        continue;
      }

      var candidates = namedCandidates[name];

      // If just one candidate, it is always valid.
      if (candidates.length == 1) {
        map[name] = candidates[0];
        continue;
      }

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

      // Candidates are recorded in forward order, so
      // `class X extends S with M1, M2 implements I1, I2 {}` will record
      // candidates from [I1, I2, S, M1, M2]. But during method lookup
      // candidates should be considered in backward order, i.e. from `M2`,
      // then from `M1`, then from `S`.
      FunctionType validOverride;
      for (var i = candidates.length - 1; i >= 0; i--) {
        validOverride = candidates[i];
        for (var j = 0; j < candidates.length; j++) {
          var candidate = candidates[j];
          if (!_typeSystem.isOverrideSubtypeOf(validOverride, candidate)) {
            validOverride = null;
            break;
          }
        }
        if (validOverride != null) {
          break;
        }
      }

      if (validOverride != null) {
        map[name] = validOverride;
      } else {
        conflicts ??= <Conflict>[];
        conflicts.add(new Conflict(name, candidates));
      }
    }

    return conflicts;
  }

  Map<Name, FunctionType> _getImplemented(InterfaceType type) {
    var implemented = _implemented[type];
    if (implemented != null) {
      return implemented;
    }

    _implemented[type] = const {};
    implemented = <Name, FunctionType>{};

    var libraryUri = type.element.librarySource.uri;

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

    void addMembers(InterfaceType type) {
      type.methods.forEach(addMember);
      type.accessors.forEach(addMember);
    }

    if (type.superclass != null) {
      var superImplemented = _getImplemented(type.superclass);
      implemented.addAll(superImplemented);
    }

    // Mixins override the nominal superclass and previous mixins.
    for (var mixin in type.mixins) {
      var superImplemented = _getImplementedInMixin(mixin);
      implemented.addAll(superImplemented);
    }

    // This type overrides everything from its actual superclass.
    addMembers(type);

    _implemented[type] = implemented;
    return implemented;
  }

  /// TODO(scheglov) This repeats a lot of code from [_getImplemented].
  Map<Name, FunctionType> _getImplementedInMixin(InterfaceType type) {
    var implemented = _mixinMembers[type];
    if (implemented != null) {
      return implemented;
    }

    _mixinMembers[type] = const {};
    implemented = <Name, FunctionType>{};

    var libraryUri = type.element.librarySource.uri;

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

    void addMembers(InterfaceType type) {
      type.methods.forEach(addMember);
      type.accessors.forEach(addMember);
    }

    for (var mixin in type.mixins) {
      var superImplemented = _getImplementedInMixin(mixin);
      implemented.addAll(superImplemented);
    }

    // This type overrides everything from its actual superclass.
    addMembers(type);

    _mixinMembers[type] = implemented;
    return implemented;
  }

  Map<Name, FunctionType> _getTypeMembers(InterfaceType type) {
    var declared = <Name, FunctionType>{};
    var libraryUri = type.element.librarySource.uri;

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

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

    return declared;
  }
}

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

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

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

  /// The map of names to their signatures from the mixins, superclasses,
  /// or interfaces.
  final Map<Name, List<FunctionType>> _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, FunctionType>> _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;

  const Interface._(
    this.map,
    this.declared,
    this._overridden,
    this._superImplemented,
    this.conflicts,
  );
}

/// 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.
  final int hashCode;

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

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

  @override
  bool operator ==(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;
}
