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

// @dart = 2.9

import 'dart:collection';

import 'package:_fe_analyzer_shared/src/messages/codes.dart'
    show Message, LocatedMessage;
import 'package:_js_interop_checks/js_interop_checks.dart';
import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
import 'package:kernel/reference_from_index.dart';
import 'package:kernel/target/changed_structure_notifier.dart';
import 'package:kernel/target/targets.dart';
import 'package:kernel/transformations/track_widget_constructor_locations.dart';

import 'constants.dart' show DevCompilerConstantsBackend;
import 'kernel_helpers.dart';

/// A kernel [Target] to configure the Dart Front End for dartdevc.
class DevCompilerTarget extends Target {
  DevCompilerTarget(this.flags);

  @override
  final TargetFlags flags;

  WidgetCreatorTracker _widgetTracker;

  Map<String, Class> _nativeClasses;

  @override
  bool get enableSuperMixins => true;

  @override
  int get enabledLateLowerings => LateLowering.all;

  @override
  bool get supportsLateLoweringSentinel => false;

  @override
  bool get useStaticFieldLowering => false;

  // TODO(johnniwinther,sigmund): Remove this when js-interop handles getter
  //  calls encoded with an explicit property get or disallows getter calls.
  @override
  bool get supportsExplicitGetterCalls => false;

  @override
  bool get supportsNewMethodInvocationEncoding => true;

  @override
  String get name => 'dartdevc';

  @override
  List<String> get extraRequiredLibraries => const [
        'dart:_runtime',
        'dart:_debugger',
        'dart:_foreign_helper',
        'dart:_interceptors',
        'dart:_internal',
        'dart:_isolate_helper',
        'dart:_js_helper',
        'dart:_js_primitives',
        'dart:_metadata',
        'dart:_native_typed_data',
        'dart:async',
        'dart:collection',
        'dart:convert',
        'dart:developer',
        'dart:io',
        'dart:isolate',
        'dart:js',
        'dart:js_util',
        'dart:math',
        'dart:typed_data',
        'dart:indexed_db',
        'dart:html',
        'dart:html_common',
        'dart:svg',
        'dart:web_audio',
        'dart:web_gl',
        'dart:web_sql'
      ];

  // The libraries required to be indexed via CoreTypes.
  @override
  List<String> get extraIndexedLibraries => const [
        'dart:async',
        'dart:collection',
        'dart:html',
        'dart:indexed_db',
        'dart:js',
        'dart:js_util',
        'dart:math',
        'dart:svg',
        'dart:web_audio',
        'dart:web_gl',
        'dart:web_sql',
        'dart:_foreign_helper',
        'dart:_interceptors',
        'dart:_js_helper',
        'dart:_native_typed_data',
        'dart:_runtime',
      ];

  @override
  bool mayDefineRestrictedType(Uri uri) =>
      uri.isScheme('dart') &&
      (uri.path == 'core' ||
          uri.path == 'typed_data' ||
          uri.path == '_interceptors' ||
          uri.path == '_native_typed_data');

  /// Returns [true] if [uri] represents a test script has been whitelisted to
  /// import private platform libraries.
  ///
  /// Unit tests for the dart:_runtime library have imports like this. It is
  /// only allowed from a specific SDK test directory or through the modular
  /// test framework.
  bool _allowedTestLibrary(Uri uri) {
    // Multi-root scheme used by modular test framework.
    if (uri.scheme == 'dev-dart-app') return true;
    return allowedNativeTest(uri);
  }

  bool _allowedDartLibrary(Uri uri) => uri.scheme == 'dart';

  @override
  bool enableNative(Uri uri) =>
      _allowedTestLibrary(uri) || _allowedDartLibrary(uri);

  @override
  bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) =>
      super.allowPlatformPrivateLibraryAccess(importer, imported) ||
      _allowedTestLibrary(importer);

  @override
  bool get nativeExtensionExpectsString => false;

  @override
  bool get errorOnUnexactWebIntLiterals => true;

  @override
  bool get enableNoSuchMethodForwarders => true;

  @override
  void performModularTransformationsOnLibraries(
      Component component,
      CoreTypes coreTypes,
      ClassHierarchy hierarchy,
      List<Library> libraries,
      Map<String, String> environmentDefines,
      DiagnosticReporter diagnosticReporter,
      ReferenceFromIndex referenceFromIndex,
      {void Function(String msg) logger,
      ChangedStructureNotifier changedStructureNotifier}) {
    _nativeClasses ??= JsInteropChecks.getNativeClasses(component);
    var jsUtilOptimizer = JsUtilOptimizer(coreTypes, hierarchy);
    for (var library in libraries) {
      _CovarianceTransformer(library).transform();
      jsUtilOptimizer.visitLibrary(library);
      JsInteropChecks(
              coreTypes,
              diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>,
              _nativeClasses)
          .visitLibrary(library);
    }
  }

  @override
  void performPreConstantEvaluationTransformations(
      Component component,
      CoreTypes coreTypes,
      List<Library> libraries,
      DiagnosticReporter diagnosticReporter,
      {void Function(String msg) logger,
      ChangedStructureNotifier changedStructureNotifier}) {
    if (flags.trackWidgetCreation) {
      _widgetTracker ??= WidgetCreatorTracker();
      _widgetTracker.transform(component, libraries, changedStructureNotifier);
    }
  }

  @override
  Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
      String name, Arguments arguments, int offset, bool isSuper) {
    // TODO(jmesserly): preserve source information?
    // (These method are synthetic. Also unclear if the offset will correspond
    // to the file where the class resides, or the file where the method we're
    // mocking resides).
    Expression createInvocation(String name, List<Expression> positional) {
      // TODO(jmesserly): this uses the implementation _Invocation class,
      // because the CFE does not resolve the redirecting factory constructors
      // like it would for user code. Our code generator expects all redirecting
      // factories to be resolved to the real constructor.
      var ctor = coreTypes.index
          .getClass('dart:core', '_Invocation')
          .constructors
          .firstWhere((c) => c.name.text == name);
      return ConstructorInvocation(ctor, Arguments(positional));
    }

    if (name.startsWith('get:')) {
      return createInvocation('getter', [SymbolLiteral(name.substring(4))]);
    }
    if (name.startsWith('set:')) {
      return createInvocation('setter',
          [SymbolLiteral(name.substring(4)), arguments.positional.single]);
    }
    var ctorArgs = <Expression>[
      SymbolLiteral(name),
      if (arguments.types.isNotEmpty)
        ListLiteral([for (var t in arguments.types) TypeLiteral(t)])
      else
        NullLiteral(),
      ListLiteral(arguments.positional),
      if (arguments.named.isNotEmpty)
        MapLiteral([
          for (var n in arguments.named)
            MapLiteralEntry(SymbolLiteral(n.name), n.value)
        ], keyType: coreTypes.symbolLegacyRawType),
    ];
    return createInvocation('method', ctorArgs);
  }

  @override
  Expression instantiateNoSuchMethodError(CoreTypes coreTypes,
      Expression receiver, String name, Arguments arguments, int offset,
      {bool isMethod = false,
      bool isGetter = false,
      bool isSetter = false,
      bool isField = false,
      bool isLocalVariable = false,
      bool isDynamic = false,
      bool isSuper = false,
      bool isStatic = false,
      bool isConstructor = false,
      bool isTopLevel = false}) {
    // TODO(sigmund): implement;
    return InvalidExpression(null);
  }

  @override
  ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
      const DevCompilerConstantsBackend();
}

/// Analyzes a component to determine if any covariance checks in private
/// members can be eliminated, and adjusts the flags to remove those checks.
///
/// See [_CovarianceTransformer.transform].
class _CovarianceTransformer extends RecursiveVisitor {
  /// The set of private instance members in [_library] that (potentially) need
  /// covariance checks.
  ///
  /// Members need checks if they are accessed through a receiver whose type is
  /// not exactly known (i.e. the actual receiver could be a subtype of its
  /// static type). If the receiver expression is `this`, `super` or non-factory
  /// instance creation, it is known to have an exact type.
  final _checkedMembers = HashSet<Member>();

  /// List of private instance procedures.
  ///
  /// [transform] uses this list to eliminate covariance flags for members that
  /// aren't in [_checkedMembers].
  final _privateProcedures = <Procedure>[];

  /// List of private instance fields.
  ///
  /// [transform] uses this list to eliminate covariance flags for members that
  /// aren't in [_checkedMembers].
  final _privateFields = <Field>[];

  final Library _library;

  _CovarianceTransformer(this._library);

  /// Transforms [_library], eliminating unncessary checks for private members.
  ///
  /// Kernel will mark covariance checks on members, for example:
  /// - a field with [Field.isGenericCovariantImpl] or [Field.isCovariant].
  /// - a method/setter with parameter(s) or type parameter(s) that have
  ///   `isGenericCovariantImpl` or `isCovariant` set.
  ///
  /// If the check can be safely eliminanted, those properties will be set to
  /// false so the JS compiler does not emit checks.
  ///
  /// Public members always need covariance checks (we cannot see all potential
  /// call sites), but in some cases we can eliminate these checks for private
  /// members.
  ///
  /// Private members only need covariance checks if they are accessed through a
  /// receiver whose type is not exactly known (i.e. the actual receiver could
  /// be a subtype of its static type). If the receiver expression is `this`,
  /// `super` or non-factory instance creation, it is known to have an exact
  /// type, so no callee check is necessary to ensure soundness (normal
  /// subtyping checks at the call site are sufficient).
  ///
  /// However to eliminate a check, we must know that all call sites are safe.
  /// So the first pass is to collect any potentially-unsafe call sites, this
  /// is done by [_checkTarget] and [_checkTearoff].
  ///
  /// Method tearoffs must also be marked potentially-unsafe, regardless of
  /// whether the receiver type is known, because they could escape. Also their
  /// runtime type must store `Object` in for covariant parameters (this
  /// affects `is`, casts, and the `.runtimeType` property).
  ///
  /// Note 1: dynamic calls do not need to be considered here, because they
  /// will be checked based on runtime type information.
  ///
  /// Node 2: public members in private classes cannot be treated as private
  /// unless we know that the member is not exposed via some public interface
  /// (implemented by their class or a subclass) that needs a covariance check.
  /// That is somewhat complex to analyze, so for now we ignore it.
  void transform() {
    _library.visitChildren(this);

    // Update the tree based on the methods that need checks.
    for (var field in _privateFields) {
      if (!_checkedMembers.contains(field)) {
        field.isCovariant = false;
        field.isGenericCovariantImpl = false;
      }
    }
    void clearCovariant(VariableDeclaration parameter) {
      parameter.isCovariant = false;
      parameter.isGenericCovariantImpl = false;
    }

    for (var member in _privateProcedures) {
      if (!_checkedMembers.contains(member)) {
        var function = member.function;
        function.positionalParameters.forEach(clearCovariant);
        function.namedParameters.forEach(clearCovariant);
        for (var t in function.typeParameters) {
          t.isGenericCovariantImpl = false;
        }
      }
    }
  }

  /// Checks if [target] is a private member called through a [receiver] that
  /// will potentially need a covariance check.
  ///
  /// If the member needs a check it will be stored in [_checkedMembers].
  ///
  /// See [transform] for more information.
  void _checkTarget(Expression receiver, Member target) {
    if (target != null &&
        target.name.isPrivate &&
        target.isInstanceMember &&
        receiver is! ThisExpression &&
        receiver is! ConstructorInvocation) {
      assert(target.enclosingLibrary == _library,
          'call to private member must be in same library');
      _checkedMembers.add(target);
    }
  }

  /// Checks if [target] is a tearoff of a private member.
  ///
  /// In this case we will need a covariance check, because the method could
  /// escape, and it also has a different runtime type.
  ///
  /// See [transform] for more information.
  void _checkTearoff(Member target) {
    if (target != null &&
        target.name.isPrivate &&
        target.isInstanceMember &&
        target is Procedure &&
        !target.isAccessor) {
      assert(target.enclosingLibrary == _library,
          'tearoff of private member must be in same library');
      _checkedMembers.add(target);
    }
  }

  @override
  void visitProcedure(Procedure node) {
    if (node.name.isPrivate &&
        // The member must be private to this library. Member signatures,
        // forwarding stubs and noSuchMethod forwarders for private members in
        // other libraries can be injected.
        node.name.library == _library &&
        node.isInstanceMember &&
        // No need to check abstract methods.
        node.function.body != null) {
      _privateProcedures.add(node);
    }
    super.visitProcedure(node);
  }

  @override
  void visitField(Field node) {
    if (node.name.isPrivate &&
        // The member must be private to this library. Member signatures,
        // forwarding stubs and noSuchMethod forwarders for private members in
        // other libraries can be injected.
        node.name.library == _library &&
        isCovariantField(node)) {
      _privateFields.add(node);
    }
    super.visitField(node);
  }

  @override
  void visitPropertyGet(PropertyGet node) {
    _checkTearoff(node.interfaceTarget);
    super.visitPropertyGet(node);
  }

  @override
  void visitInstanceGet(InstanceGet node) {
    _checkTearoff(node.interfaceTarget);
    super.visitInstanceGet(node);
  }

  @override
  void visitPropertySet(PropertySet node) {
    _checkTarget(node.receiver, node.interfaceTarget);
    super.visitPropertySet(node);
  }

  @override
  void visitInstanceSet(InstanceSet node) {
    _checkTarget(node.receiver, node.interfaceTarget);
    super.visitInstanceSet(node);
  }

  @override
  void visitMethodInvocation(MethodInvocation node) {
    _checkTarget(node.receiver, node.interfaceTarget);
    super.visitMethodInvocation(node);
  }

  @override
  void visitInstanceInvocation(InstanceInvocation node) {
    _checkTarget(node.receiver, node.interfaceTarget);
    super.visitInstanceInvocation(node);
  }

  @override
  void visitInstanceGetterInvocation(InstanceGetterInvocation node) {
    _checkTarget(node.receiver, node.interfaceTarget);
    super.visitInstanceGetterInvocation(node);
  }

  @override
  void visitInstanceTearOff(InstanceTearOff node) {
    _checkTearoff(node.interfaceTarget);
    super.visitInstanceTearOff(node);
  }

  @override
  void visitEqualsCall(EqualsCall node) {
    _checkTarget(node.left, node.interfaceTarget);
    super.visitEqualsCall(node);
  }
}

List<Pattern> _allowedNativeTestPatterns = [
  'tests/dartdevc',
  'tests/web/native',
  'tests/web_2/native',
  'tests/web/internal',
  'tests/web_2/internal',
];

bool allowedNativeTest(Uri uri) {
  var path = uri.path;
  return _allowedNativeTestPatterns.any((pattern) => path.contains(pattern));
}
