// 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.

part of 'declaration_builders.dart';

const Uri? noUri = null;

abstract class ClassMemberAccess {
  /// [Iterator] for all constructors declared in this class or any of its
  /// augmentations.
  ///
  /// Duplicates and augmenting constructor are _not_ included.
  ///
  /// For instance:
  ///
  ///     class Class {
  ///       Class(); // declared, so it is included
  ///       Class.named(); // declared, so it is included
  ///       Class.named(); // duplicate, so it is *not* included
  ///     }
  ///
  ///     augment class Class {
  ///       augment Class(); // augmenting, so it is *not* included
  ///       Class.extra(); // declared, so it is included
  ///     }
  ///
  Iterator<T> fullConstructorIterator<T extends MemberBuilder>();

  /// [NameIterator] for all constructors declared in this class or any of its
  /// augmentations.
  ///
  /// Duplicates and augmenting constructors are _not_ included.
  ///
  /// For instance:
  ///
  ///     class Class {
  ///       Class(); // declared, so it is included
  ///       Class.named(); // declared, so it is included
  ///       Class.named(); // duplicate, so it is *not* included
  ///     }
  ///
  ///     augment class Class {
  ///       augment Class(); // augmenting, so it is *not* included
  ///       Class.extra(); // declared, so it is included
  ///     }
  ///
  NameIterator<T> fullConstructorNameIterator<T extends MemberBuilder>();

  /// [Iterator] for all members declared in this class or any of its
  /// augmentations.
  ///
  /// Duplicates and augmenting members are _not_ included.
  ///
  /// For instance:
  ///
  ///     class Class {
  ///       method() {} // Declared, so it is included.
  ///       method2() {} // Declared, so it is included.
  ///       method2() {} // Duplicate, so it is *not* included.
  ///     }
  ///
  ///     augment class Class {
  ///       augment method() {} // Augmenting, so it is *not* included.
  ///       extra() {} // Declared, so it is included.
  ///     }
  ///
  Iterator<T> fullMemberIterator<T extends Builder>();

  /// [NameIterator] for all members declared in this class or any of its
  /// augmentations.
  ///
  /// Duplicates and augmenting members are _not_ included.
  ///
  /// For instance:
  ///
  ///     class Class {
  ///       method() {} // Declared, so it is included.
  ///       method2() {} // Declared, so it is included.
  ///       method2() {} // Duplicate, so it is *not* included.
  ///     }
  ///
  ///     augment class Class {
  ///       augment method() {} // Augmenting, so it is *not* included.
  ///       extra() {} // Declared, so it is included.
  ///     }
  ///
  NameIterator<T> fullMemberNameIterator<T extends Builder>();
}

abstract class ClassBuilder implements DeclarationBuilder, ClassMemberAccess {
  /// The type variables declared on a class, extension or mixin declaration.
  List<NominalVariableBuilder>? get typeVariables;

  /// The type in the `extends` clause of a class declaration.
  ///
  /// Currently this also holds the synthesized super class for a mixin
  /// declaration.
  TypeBuilder? get supertypeBuilder;

  /// The type in the `implements` clause of a class or mixin declaration.
  List<TypeBuilder>? get interfaceBuilders;

  /// The types in the `on` clause of an extension or mixin declaration.
  List<TypeBuilder>? get onTypes;

  @override
  Uri get fileUri;

  bool get isAbstract;

  bool get isMacro;

  bool get isSealed;

  bool get isBase;

  bool get isInterface;

  @override
  bool get isFinal;

  bool get declaresConstConstructor;

  bool get isMixinClass;

  bool get isMixinDeclaration;

  bool get isMixinApplication;

  bool get isAnonymousMixinApplication;

  abstract TypeBuilder? mixedInTypeBuilder;

  /// The [Class] built by this builder.
  ///
  /// For an augmentation class the origin class is returned.
  Class get cls;

  @override
  ClassBuilder get origin;

  abstract bool isNullClass;

  @override
  InterfaceType get thisType;

  Supertype buildMixedInType(
      LibraryBuilder library, List<TypeBuilder>? arguments);

  /// Looks up the member by [name] on the class built by this class builder.
  ///
  /// If [isSetter] is `false`, only fields, methods, and getters with that name
  /// will be found.  If [isSetter] is `true`, only non-final fields and setters
  /// will be found.
  ///
  /// If [isSuper] is `false`, the member is found among the interface members
  /// the class built by this class builder. If [isSuper] is `true`, the member
  /// is found among the class members of the superclass.
  ///
  /// If this class builder is an augmentation, interface members declared in
  /// this augmentation are searched before searching the interface members in
  /// the origin class.
  ///
  /// Unused in interface; left in on purpose.
  Member? lookupInstanceMember(ClassHierarchy hierarchy, Name name,
      {bool isSetter = false, bool isSuper = false});
}

abstract class ClassBuilderImpl extends DeclarationBuilderImpl
    implements ClassBuilder {
  @override
  bool isNullClass = false;

  InterfaceType? _legacyRawType;
  InterfaceType? _nullableRawType;
  InterfaceType? _nonNullableRawType;
  InterfaceType? _thisType;

  ClassBuilderImpl(List<MetadataBuilder>? metadata, int modifiers, String name,
      LibraryBuilder parent, int charOffset)
      : super(metadata, modifiers, name, parent, charOffset);

  @override
  String get debugName => "ClassBuilder";

  @override
  bool get isAbstract => (modifiers & abstractMask) != 0;

  @override
  bool get isMixinApplication => mixedInTypeBuilder != null;

  @override
  bool get isNamedMixinApplication {
    return isMixinApplication && (modifiers & namedMixinApplicationMask) != 0;
  }

  @override
  bool get isAnonymousMixinApplication {
    return isMixinApplication &&
        // Coverage-ignore(suite): Not run.
        !isNamedMixinApplication;
  }

  @override
  bool get declaresConstConstructor =>
      (modifiers & declaresConstConstructorMask) != 0;

  @override
  Builder? findStaticBuilder(
      String name, int charOffset, Uri fileUri, LibraryBuilder accessingLibrary,
      {bool isSetter = false}) {
    if (accessingLibrary.nameOriginBuilder.origin !=
            libraryBuilder.nameOriginBuilder.origin &&
        name.startsWith("_")) {
      return null;
    }
    Builder? declaration = normalizeLookup(
        getable: nameSpace.lookupLocalMember(name, setter: false),
        setable: nameSpace.lookupLocalMember(name, setter: true),
        name: name,
        charOffset: charOffset,
        fileUri: fileUri,
        classNameOrDebugName: this.name,
        isSetter: isSetter,
        forStaticAccess: true);
    if (declaration == null && isAugmenting) {
      return origin.findStaticBuilder(
          name, charOffset, fileUri, accessingLibrary,
          isSetter: isSetter);
    }
    return declaration;
  }

  @override
  Builder? lookupLocalMember(String name,
      {bool setter = false, bool required = false}) {
    Builder? builder = nameSpace.lookupLocalMember(name, setter: setter);
    if (builder == null && isAugmenting) {
      // Coverage-ignore-block(suite): Not run.
      builder = origin.nameSpace.lookupLocalMember(name, setter: setter);
    }
    if (required && builder == null) {
      internalProblem(
          templateInternalProblemNotFoundIn.withArguments(
              name, fullNameForErrors),
          -1,
          null);
    }
    return builder;
  }

  /// Find the first member of this class with [name]. This method isn't
  /// suitable for scope lookups as it will throw an error if the name isn't
  /// declared. The [scope] should be used for that. This method is used to
  /// find a member that is known to exist and it will pick the first
  /// declaration if the name is ambiguous.
  ///
  /// For example, this method is convenient for use when building synthetic
  /// members, such as those of an enum.
  MemberBuilder? firstMemberNamed(String name) {
    MemberBuilder declaration =
        lookupLocalMember(name, required: true) as MemberBuilder;
    while (declaration.next != null) {
      declaration = declaration.next as MemberBuilder;
    }
    return declaration;
  }

  @override
  InterfaceType get thisType {
    return _thisType ??= new InterfaceType(cls, Nullability.nonNullable,
        getAsTypeArguments(cls.typeParameters, libraryBuilder.library));
  }

  // Coverage-ignore(suite): Not run.
  InterfaceType get legacyRawType {
    return _legacyRawType ??= new InterfaceType(cls, Nullability.legacy,
        new List<DartType>.filled(typeVariablesCount, const DynamicType()));
  }

  InterfaceType get nullableRawType {
    return _nullableRawType ??= new InterfaceType(cls, Nullability.nullable,
        new List<DartType>.filled(typeVariablesCount, const DynamicType()));
  }

  InterfaceType get nonNullableRawType {
    return _nonNullableRawType ??= new InterfaceType(
        cls,
        Nullability.nonNullable,
        new List<DartType>.filled(typeVariablesCount, const DynamicType()));
  }

  InterfaceType rawType(Nullability nullability) {
    switch (nullability) {
      case Nullability.legacy:
        // Coverage-ignore(suite): Not run.
        return legacyRawType;
      case Nullability.nullable:
        return nullableRawType;
      case Nullability.nonNullable:
        return nonNullableRawType;
      // Coverage-ignore(suite): Not run.
      case Nullability.undetermined:
        return unhandled("$nullability", "rawType", TreeNode.noOffset, noUri);
    }
  }

  InterfaceType? aliasedTypeWithBuiltArgumentsCacheNonNullable;
  InterfaceType? aliasedTypeWithBuiltArgumentsCacheNullable;

  @override
  DartType buildAliasedTypeWithBuiltArguments(
      LibraryBuilder library,
      Nullability nullability,
      List<DartType> arguments,
      TypeUse typeUse,
      Uri fileUri,
      int charOffset,
      {required bool hasExplicitTypeArguments}) {
    assert(cls.typeParameters.length == arguments.length);
    if (isNullClass) {
      return const NullType();
    }
    if (name == "FutureOr") {
      LibraryBuilder parentLibrary = parent as LibraryBuilder;
      if (parentLibrary.importUri.isScheme("dart") &&
          parentLibrary.importUri.path == "async") {
        assert(arguments.length == 1);
        return new FutureOrType(arguments.single, nullability);
      }
    }
    if (arguments.isEmpty) {
      return rawType(nullability);
    }
    if (aliasedTypeWithBuiltArgumentsCacheNonNullable != null &&
        // Coverage-ignore(suite): Not run.
        nullability == Nullability.nonNullable) {
      // Coverage-ignore-block(suite): Not run.
      assert(aliasedTypeWithBuiltArgumentsCacheNonNullable!.classReference ==
          cls.reference);
      assert(arguments.isEmpty);
      return aliasedTypeWithBuiltArgumentsCacheNonNullable!;
    } else if (aliasedTypeWithBuiltArgumentsCacheNullable != null &&
        // Coverage-ignore(suite): Not run.
        nullability == Nullability.nullable) {
      // Coverage-ignore-block(suite): Not run.
      assert(aliasedTypeWithBuiltArgumentsCacheNullable!.classReference ==
          cls.reference);
      assert(arguments.isEmpty);
      return aliasedTypeWithBuiltArgumentsCacheNullable!;
    }
    InterfaceType type = new InterfaceType(cls, nullability, arguments);
    if (arguments.isEmpty) {
      // Coverage-ignore-block(suite): Not run.
      assert(typeVariablesCount == 0);
      if (nullability == Nullability.nonNullable) {
        aliasedTypeWithBuiltArgumentsCacheNonNullable = type;
      } else if (nullability == Nullability.nullable) {
        aliasedTypeWithBuiltArgumentsCacheNullable = type;
      }
    }

    if (typeVariablesCount != 0 && library is SourceLibraryBuilder) {
      library.registerBoundsCheck(type, fileUri, charOffset, typeUse,
          inferred: !hasExplicitTypeArguments);
    }
    return type;
  }

  @override
  DartType buildAliasedType(
      LibraryBuilder library,
      NullabilityBuilder nullabilityBuilder,
      List<TypeBuilder>? arguments,
      TypeUse typeUse,
      Uri fileUri,
      int charOffset,
      ClassHierarchyBase? hierarchy,
      {required bool hasExplicitTypeArguments}) {
    if (name == "Record" &&
        libraryBuilder.importUri.scheme == "dart" &&
        libraryBuilder.importUri.path == "core" &&
        library is SourceLibraryBuilder &&
        !isRecordAccessAllowed(library)) {
      // Coverage-ignore-block(suite): Not run.
      library.reportFeatureNotEnabled(
          library.libraryFeatures.records, fileUri, charOffset, name.length);
      return const InvalidType();
    }
    return buildAliasedTypeWithBuiltArguments(
        library,
        nullabilityBuilder.build(),
        buildAliasedTypeArguments(library, arguments, hierarchy),
        typeUse,
        fileUri,
        charOffset,
        hasExplicitTypeArguments: hasExplicitTypeArguments);
  }

  @override
  Supertype buildMixedInType(
      LibraryBuilder library, List<TypeBuilder>? arguments) {
    Class cls = isAugmenting
        ?
        // Coverage-ignore(suite): Not run.
        origin.cls
        : this.cls;
    if (arguments != null) {
      List<DartType> typeArguments =
          buildAliasedTypeArguments(library, arguments, /* hierarchy = */ null);
      typeArguments = unaliasTypes(typeArguments, legacyEraseAliases: false)!;
      return new Supertype(cls, typeArguments);
    } else {
      return new Supertype(
          cls,
          new List<DartType>.filled(
              cls.typeParameters.length, const UnknownType(),
              growable: true));
    }
  }

  @override
  String get fullNameForErrors {
    return isMixinApplication && !isNamedMixinApplication
        ? "${supertypeBuilder!.fullNameForErrors} with "
            "${mixedInTypeBuilder!.fullNameForErrors}"
        : name;
  }

  @override
  Member? lookupInstanceMember(ClassHierarchy hierarchy, Name name,
      {bool isSetter = false, bool isSuper = false}) {
    Class? instanceClass = cls;
    if (isAugmenting) {
      // Coverage-ignore-block(suite): Not run.
      assert(identical(instanceClass, origin.cls),
          "Found ${origin.cls} expected $instanceClass");
      if (isSuper) {
        // The super class is only correctly found through the origin class.
        instanceClass = origin.cls;
      } else {
        Member? member =
            hierarchy.getInterfaceMember(instanceClass, name, setter: isSetter);
        if (member?.parent == instanceClass) {
          // Only if the member is found in the augmentation can we use it.
          return member;
        } else {
          // Otherwise, we need to keep searching in the origin class.
          instanceClass = origin.cls;
        }
      }
    }

    if (isSuper) {
      instanceClass = instanceClass.superclass;
      if (instanceClass == null) return null;
    }
    Member? target = isSuper
        ? hierarchy.getDispatchTarget(instanceClass, name, setter: isSetter)
        :
        // Coverage-ignore(suite): Not run.
        hierarchy.getInterfaceMember(instanceClass, name, setter: isSetter);
    if (isSuper && target == null) {
      if (cls.isMixinDeclaration) {
        target =
            hierarchy.getInterfaceMember(instanceClass, name, setter: isSetter);
      }
    }
    return target;
  }
}

class ConstructorRedirection {
  String target;
  bool cycleReported;

  ConstructorRedirection(this.target) : cycleReported = false;
}
