// Copyright (c) 2021, 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 fasta.class_hierarchy_builder;

import 'package:kernel/ast.dart';

import '../../builder/class_builder.dart';
import '../../messages.dart'
    show
        LocatedMessage,
        messageDeclaredMemberConflictsWithOverriddenMembersCause,
        templateCombinedMemberSignatureFailed;
import '../../source/source_class_builder.dart';
import '../../source/source_library_builder.dart' show SourceLibraryBuilder;
import '../combined_member_signature.dart';
import '../forwarding_node.dart' show ForwardingNode;
import '../member_covariance.dart';
import 'members_builder.dart';

abstract class ClassMember {
  Name get name;
  bool get isStatic;
  bool get isField;
  bool get isAssignable;
  bool get isSetter;
  bool get isGetter;
  bool get isFinal;
  bool get isConst;
  bool get forSetter;

  /// Returns `true` if this member corresponds to a declaration in the source
  /// code.
  bool get isSourceDeclaration;

  /// Returns `true` if this member is a field, getter or setter.
  bool get isProperty;

  /// Computes the [Member] node resulting from this class member.
  Member getMember(ClassMembersBuilder membersBuilder);

  /// Returns the member [Covariance] for this class member.
  Covariance getCovariance(ClassMembersBuilder membersBuilder);

  bool get isDuplicate;
  String get fullName;
  String get fullNameForErrors;
  ClassBuilder get classBuilder;

  /// Returns `true` if this class member is declared in Object from dart:core.
  bool isObjectMember(ClassBuilder objectClass);
  Uri get fileUri;
  int get charOffset;

  /// Returns `true` if this class member is an interface member.
  bool get isAbstract;

  /// Returns `true` if this member doesn't corresponds to a declaration in the
  /// source code.
  bool get isSynthesized;

  // If `true` this member is not part of the interface but only part of the
  // class members.
  //
  // This is `true` for instance for synthesized fields added for the late
  // lowering.
  bool get isInternalImplementation;

  /// Returns `true` if this member is composed from a list of class members
  /// accessible through [declarations].
  bool get hasDeclarations;

  /// If [hasDeclaration] is `true`, this returns the list of class members
  /// from which this class member is composed.
  ///
  /// This is used in [unfoldDeclarations] to retrieve all underlying member
  /// source declarations, and in [toSet] to retrieve all members used for
  /// this class member wrt. certain level of the hierarchy.
  /// TODO(johnniwinther): Can the use of [toSet] be replaced with a direct
  /// use of [declarations]?
  List<ClassMember> get declarations;

  /// The interface member corresponding to this member.
  ///
  /// If this member is declared on the source, the interface member is
  /// the member itself. For instance
  ///
  ///     abstract class Class {
  ///        void concreteMethod() {}
  ///        void abstractMethod();
  ///     }
  ///
  /// the interface members for `concreteMethod` and `abstractMethod` are the
  /// members themselves.
  ///
  /// If this member is a synthesized interface member, the
  /// interface member is the member itself. For instance
  ///
  ///     abstract class Interface1 {
  ///        void method() {}
  ///     }
  ///     abstract class Interface2 {
  ///        void method() {}
  ///     }
  ///     abstract class Class implements Interface1, Interface2 {}
  ///
  /// the interface member for `method` in `Class` is the synthesized interface
  /// member created for the implemented members `Interface1.method` and
  /// `Interface2.method`.
  ///
  /// If this member is a concrete member that implements an interface member,
  /// the interface member is the implemented interface member. For instance
  ///
  ///     class Super {
  ///        void method() {}
  ///     }
  ///     class Interface {
  ///        void method() {}
  ///     }
  ///     class Class extends Super implements Interface {}
  ///
  /// the interface member for `Super.method` implementing `method` in `Class`
  /// is the synthesized interface member created for the implemented members
  /// `Super.method` and `Interface.method`.
  ClassMember get interfaceMember;

  void inferType(ClassMembersBuilder membersBuilder);
  void registerOverrideDependency(Set<ClassMember> overriddenMembers);

  /// Returns `true` if this has the same underlying declaration as [other].
  ///
  /// This is used for avoiding unnecessary checks and can this trivially
  /// return `false`.
  bool isSameDeclaration(ClassMember other);
}

abstract class SynthesizedMember extends ClassMember {
  @override
  final ClassBuilder classBuilder;

  @override
  final Name name;

  @override
  final bool forSetter;

  @override
  final bool isProperty;

  SynthesizedMember(this.classBuilder, this.name,
      {required this.forSetter, required this.isProperty})
      // ignore: unnecessary_null_comparison
      : assert(forSetter != null),
        // ignore: unnecessary_null_comparison
        assert(isProperty != null);

  @override
  List<ClassMember> get declarations => throw new UnimplementedError();

  @override
  void inferType(ClassMembersBuilder membersBuilder) {}

  @override
  bool get isAssignable => throw new UnimplementedError();

  @override
  bool get isConst => throw new UnimplementedError();

  @override
  bool get isDuplicate => false;

  @override
  bool get isField => throw new UnimplementedError();

  @override
  bool get isFinal => throw new UnimplementedError();

  @override
  bool get isGetter => throw new UnimplementedError();

  @override
  bool get isInternalImplementation => false;

  @override
  bool get isSetter => forSetter;

  @override
  bool get isSourceDeclaration => false;

  @override
  bool get isStatic => false;

  @override
  bool get isSynthesized => true;

  @override
  void registerOverrideDependency(Set<ClassMember> overriddenMembers) {}
}

/// Class member for a set of interface members.
///
/// This is used to compute combined member signature of a set of interface
/// members inherited into the same class, and to insert forwarding stubs,
/// mixin stubs, and member signatures where needed.
class SynthesizedInterfaceMember extends SynthesizedMember {
  @override
  final List<ClassMember> declarations;

  /// The concrete member in the super class overridden by [declarations], if
  /// any.
  ///
  /// This is used to as the target when creating concrete forwarding and mixin
  /// stub. For instance:
  ///
  ///    class Super {
  ///      method(int i) {}
  ///    }
  ///    class Interface {
  ///      method(covariant int i) {}
  ///    }
  ///    class Class extends Super implements Interface {
  ///      // Concrete forwarding stub calling [_superClassMember]:
  ///      method(covariant int i) => super.method(i);
  ///
  final ClassMember? _superClassMember;

  /// The canonical member of the combined member signature if it is known by
  /// construction. The canonical member defines the type of combined member
  /// signature.
  ///
  /// This is used when a declared member is part of a set of implemented
  /// members. For instance
  ///
  ///     class Super {
  ///       method(int i) {}
  ///     }
  ///     class Interface {
  ///       method(covariant num i) {}
  ///     }
  ///     class Class implements Interface {
  ///       // This member is updated to be a concrete forwarding stub with an
  ///       // covariant parameter but with its declared parameter type:
  ///       //    method(covariant int i) => super.method(i);
  ///       method(int i);
  ///     }
  final ClassMember? _canonicalMember;

  /// The member in [declarations] that is mixed in, if any.
  ///
  /// This is used to create mixin stubs. If the mixed in member is abstract,
  /// an abstract mixin stub is created:
  ///
  ///    class Super {
  ///      void method() {}
  ///    }
  ///    class Mixin {
  ///      void method();
  ///    }
  ///    // Abstract mixin stub with `Mixin.method` as target inserted:
  ///    //   void method();
  ///    class Class = Super with Mixin;
  ///
  /// If the mixed in member is concrete, a concrete mixin member is created:
  ///
  ///    class Super {
  ///      void method() {}
  ///    }
  ///    class Mixin {
  ///      void method() {}
  ///    }
  ///    // Concrete mixin stub with `Mixin.method` as target inserted:
  ///    //   void method() => super.method();
  ///    class Class = Super with Mixin;
  ///
  /// If a forwarding stub is needed, the created stub will be a possibly
  /// concrete forwarding stub:
  ///
  ///    class Super {
  ///      void method(int i) {}
  ///    }
  ///    class Interface {
  ///      void method(covariant num i) {}
  ///    }
  ///    class Mixin {
  ///      void method(int i);
  ///    }
  ///    // Concrete forwarding stub with `Super.method` as target inserted:
  ///    //   void method(covariant int i) => super.method(i);
  ///    class Class = Super with Mixin implements Interface;
  ///
  final ClassMember? _mixedInMember;

  /// If `true`, a stub should be inserted, if needed.
  final bool _shouldModifyKernel;

  Member? _member;
  Covariance? _covariance;

  SynthesizedInterfaceMember(
      ClassBuilder classBuilder, Name name, this.declarations,
      {ClassMember? superClassMember,
      ClassMember? canonicalMember,
      ClassMember? mixedInMember,
      required bool isProperty,
      required bool forSetter,
      required bool shouldModifyKernel})
      : this._superClassMember = superClassMember,
        this._canonicalMember = canonicalMember,
        this._mixedInMember = mixedInMember,
        this._shouldModifyKernel = shouldModifyKernel,
        super(classBuilder, name, isProperty: isProperty, forSetter: forSetter);

  @override
  bool get hasDeclarations => true;

  void _ensureMemberAndCovariance(ClassMembersBuilder membersBuilder) {
    if (_member != null) {
      return;
    }
    if (classBuilder.library is! SourceLibraryBuilder) {
      if (_canonicalMember != null) {
        _member = _canonicalMember!.getMember(membersBuilder);
        _covariance = _canonicalMember!.getCovariance(membersBuilder);
      } else {
        _member = declarations.first.getMember(membersBuilder);
        _covariance = declarations.first.getCovariance(membersBuilder);
      }
      return;
    }
    CombinedClassMemberSignature combinedMemberSignature;
    if (_canonicalMember != null) {
      combinedMemberSignature = new CombinedClassMemberSignature.internal(
          membersBuilder,
          classBuilder as SourceClassBuilder,
          declarations.indexOf(_canonicalMember!),
          declarations,
          forSetter: isSetter);
    } else {
      combinedMemberSignature = new CombinedClassMemberSignature(
          membersBuilder, classBuilder as SourceClassBuilder, declarations,
          forSetter: isSetter);

      if (combinedMemberSignature.canonicalMember == null) {
        String name = classBuilder.fullNameForErrors;
        int length = classBuilder.isAnonymousMixinApplication ? 1 : name.length;
        List<LocatedMessage> context = declarations.map((ClassMember d) {
          return messageDeclaredMemberConflictsWithOverriddenMembersCause
              .withLocation(
                  d.fileUri, d.charOffset, d.fullNameForErrors.length);
        }).toList();

        classBuilder.addProblem(
            templateCombinedMemberSignatureFailed.withArguments(
                classBuilder.fullNameForErrors,
                declarations.first.fullNameForErrors),
            classBuilder.charOffset,
            length,
            context: context);
        // TODO(johnniwinther): Maybe we should have an invalid marker to avoid
        // cascading errors.
        _member = declarations.first.getMember(membersBuilder);
        _covariance = declarations.first.getCovariance(membersBuilder);
        return;
      }
    }

    if (_shouldModifyKernel) {
      ProcedureKind kind = ProcedureKind.Method;
      Member canonicalMember =
          combinedMemberSignature.canonicalMember!.getMember(membersBuilder);
      if (combinedMemberSignature.canonicalMember!.isProperty) {
        kind = isSetter ? ProcedureKind.Setter : ProcedureKind.Getter;
      } else if (canonicalMember is Procedure &&
          canonicalMember.kind == ProcedureKind.Operator) {
        kind = ProcedureKind.Operator;
      }

      Procedure? stub = new ForwardingNode(
              combinedMemberSignature, kind, _superClassMember, _mixedInMember)
          .finalize();
      if (stub != null) {
        assert(classBuilder.cls == stub.enclosingClass);
        assert(stub != canonicalMember);
        classBuilder.cls.addProcedure(stub);
        SourceLibraryBuilder library =
            classBuilder.library as SourceLibraryBuilder;
        if (canonicalMember is Procedure) {
          library.forwardersOrigins
            ..add(stub)
            ..add(canonicalMember);
        }
        _member = stub;
        _covariance = combinedMemberSignature.combinedMemberSignatureCovariance;
        assert(
            _covariance ==
                new Covariance.fromMember(_member!, forSetter: forSetter),
            "Unexpected covariance for combined members signature "
            "$_member. Found $_covariance, expected "
            "${new Covariance.fromMember(_member!, forSetter: forSetter)}.");
        return;
      }
    }

    _member =
        combinedMemberSignature.canonicalMember!.getMember(membersBuilder);
    _covariance = combinedMemberSignature.combinedMemberSignatureCovariance;
  }

  @override
  Member getMember(ClassMembersBuilder membersBuilder) {
    _ensureMemberAndCovariance(membersBuilder);
    return _member!;
  }

  @override
  Covariance getCovariance(ClassMembersBuilder membersBuilder) {
    _ensureMemberAndCovariance(membersBuilder);
    return _covariance!;
  }

  @override
  ClassMember get interfaceMember => this;

  @override
  bool isObjectMember(ClassBuilder objectClass) {
    return false;
  }

  @override
  bool isSameDeclaration(ClassMember other) {
    // TODO(johnniwinther): Optimize this.
    return false;
  }

  @override
  int get charOffset => declarations.first.charOffset;

  @override
  Uri get fileUri => declarations.first.fileUri;

  @override
  bool get isAbstract => true;

  @override
  String get fullNameForErrors =>
      declarations.map((ClassMember m) => m.fullName).join("%");

  @override
  String get fullName {
    String suffix = isSetter ? "=" : "";
    return "${fullNameForErrors}$suffix";
  }

  @override
  String toString() => 'SynthesizedInterfaceMember($classBuilder,$name,'
      '$declarations,forSetter=$forSetter)';
}

/// Class member for an inherited concrete member that implements an interface
/// member.
///
/// This is used to ensure that both the inherited concrete member and the
/// interface member is taken into account when computing the resulting [Member]
/// node.
///
/// This is needed because an interface member, though initially abstract, can
/// result in a concrete stub that overrides the concrete member. For instance
///
///    class Super {
///      method(int i) {}
///    }
///    class Interface {
///      method(covariant int i) {}
///    }
///    class Class extends Super implements Interface {
///      // A concrete forwarding stub is inserted:
///      method(covariant int i) => super.method(i);
///    }
///    class Sub extends Class implements Interface {
///      // No forwarding stub should be inserted since `Class.method` is
///      // adequate.
///    }
///
///
///  Here the create stub `Class.method` overrides `Super.method` and should
///  be used to determine whether to insert a forwarding stub in subclasses.
class InheritedClassMemberImplementsInterface extends SynthesizedMember {
  final ClassMember inheritedClassMember;
  final ClassMember implementedInterfaceMember;

  Member? _member;
  Covariance? _covariance;

  InheritedClassMemberImplementsInterface(ClassBuilder classBuilder, Name name,
      {required this.inheritedClassMember,
      required this.implementedInterfaceMember,
      required bool isProperty,
      required bool forSetter})
      // ignore: unnecessary_null_comparison
      : assert(inheritedClassMember != null),
        // ignore: unnecessary_null_comparison
        assert(implementedInterfaceMember != null),
        super(classBuilder, name, isProperty: isProperty, forSetter: forSetter);

  void _ensureMemberAndCovariance(ClassMembersBuilder membersBuilder) {
    if (_member == null) {
      Member classMember = inheritedClassMember.getMember(membersBuilder);
      Member interfaceMember =
          implementedInterfaceMember.getMember(membersBuilder);
      if (!interfaceMember.isAbstract &&
          interfaceMember.enclosingClass == classBuilder.cls) {
        /// The interface member resulted in a concrete stub being inserted.
        /// For instance for `method1` but _not_ for `method2` here:
        ///
        ///    class Super {
        ///      method1(int i) {}
        ///      method2(covariant int i) {}
        ///    }
        ///    class Interface {
        ///      method1(covariant int i) {}
        ///      method2(int i) {}
        ///    }
        ///    class Class extends Super implements Interface {
        ///      // A concrete forwarding stub is inserted for `method1` since
        ///      // the parameter on `Super.method1` is _not_ marked as
        ///      // covariant:
        ///      method1(covariant int i) => super.method(i);
        ///      // No concrete forwarding stub is inserted for `method2` since
        ///      // the parameter on `Super.method2` is already marked as
        ///      // covariant.
        ///    }
        ///
        /// The inserted stub should be used as the resulting member.
        _member = interfaceMember;
        _covariance = implementedInterfaceMember.getCovariance(membersBuilder);
      } else {
        /// The interface member did not result in an inserted stub or the
        /// inserted stub was abstract. For instance:
        ///
        ///    // Opt-in:
        ///    class Super {
        ///      method(int? i) {}
        ///    }
        ///    // Opt-out:
        ///    class Class extends Super {
        ///      // An abstract member signature stub is inserted:
        ///      method(int* i);
        ///    }
        ///
        /// The inserted stub should _not_ be used as the resulting member
        /// since it is abstract and therefore not a class member.
        _member = classMember;
        _covariance = inheritedClassMember.getCovariance(membersBuilder);
      }
    }
  }

  @override
  Member getMember(ClassMembersBuilder membersBuilder) {
    _ensureMemberAndCovariance(membersBuilder);
    return _member!;
  }

  @override
  Covariance getCovariance(ClassMembersBuilder membersBuilder) {
    _ensureMemberAndCovariance(membersBuilder);
    return _covariance!;
  }

  @override
  ClassMember get interfaceMember => implementedInterfaceMember;

  @override
  bool isObjectMember(ClassBuilder objectClass) {
    return inheritedClassMember.isObjectMember(objectClass);
  }

  @override
  bool isSameDeclaration(ClassMember other) {
    // TODO(johnniwinther): Optimize this.
    return false;
  }

  @override
  int get charOffset => inheritedClassMember.charOffset;

  @override
  Uri get fileUri => inheritedClassMember.fileUri;

  @override
  bool get hasDeclarations => false;

  @override
  bool get isAbstract => false;

  @override
  String get fullNameForErrors => inheritedClassMember.fullNameForErrors;

  @override
  String get fullName => inheritedClassMember.fullName;

  @override
  String toString() =>
      'InheritedClassMemberImplementsInterface($classBuilder,$name,'
      'inheritedClassMember=$inheritedClassMember,'
      'implementedInterfaceMember=$implementedInterfaceMember,'
      'forSetter=$forSetter)';
}
