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

library vm.transformations.no_dynamic_invocations_annotator;

import 'package:kernel/ast.dart';

import '../metadata/procedure_attributes.dart';

/// Assumes strong mode and closed world. If a procedure can not be riched
/// via dynamic invocation from anywhere then annotates it with appropriate
/// [ProcedureAttributeMetadata] annotation.
Component transformComponent(Component component) {
  new NoDynamicUsesAnnotator(component).visitComponent(component);
  return component;
}

enum Action { get, set, invoke }

class Selector {
  final Action action;
  final Name target;

  Selector(this.action, this.target);

  Selector.doInvoke(Name target) : this(Action.invoke, target);
  Selector.doGet(Name target) : this(Action.get, target);
  Selector.doSet(Name target) : this(Action.set, target);

  bool operator ==(other) {
    return other is Selector &&
        other.action == this.action &&
        other.target == this.target;
  }

  int get hashCode => (action.index * 31) ^ target.hashCode;

  @override
  String toString() {
    switch (action) {
      case Action.get:
        return 'get:${target}';
      case Action.set:
        return 'set:${target}';
      case Action.invoke:
        return '${target}';
    }
    return '?';
  }
}

// TODO(kustermann): Try to extend the idea of tracking uses based on the 'this'
// hierarchy.
class NoDynamicUsesAnnotator {
  final DynamicSelectorsCollector _selectors;
  final ProcedureAttributesMetadataRepository _metadata;

  NoDynamicUsesAnnotator(Component component)
      : _selectors = DynamicSelectorsCollector.collect(component),
        _metadata = new ProcedureAttributesMetadataRepository() {
    component.addMetadataRepository(_metadata);
  }

  visitComponent(Component component) {
    for (var library in component.libraries) {
      for (var klass in library.classes) {
        visitClass(klass);
      }
    }
  }

  visitClass(Class node) {
    for (var member in node.members) {
      if (member is Procedure) {
        visitProcedure(member);
      } else if (member is Field) {
        visitField(member);
      }
    }
  }

  visitField(Field node) {
    if (node.isStatic || node.name.name == 'call') {
      return;
    }

    final selector = new Selector.doSet(node.name);
    if (_selectors.dynamicSelectors.contains(selector)) {
      return;
    }

    ProcedureAttributesMetadata metadata;
    if (!_selectors.nonThisSelectors.contains(selector)) {
      metadata = const ProcedureAttributesMetadata(
          methodOrSetterCalledDynamically: false,
          getterCalledDynamically: false,
          hasNonThisUses: true,
          hasTearOffUses: false);
    } else {
      metadata = const ProcedureAttributesMetadata.noDynamicUses();
    }
    _metadata.mapping[node] = metadata;
  }

  visitProcedure(Procedure node) {
    if (node.isStatic || node.name.name == 'call') {
      return;
    }

    Selector selector;
    if (node.kind == ProcedureKind.Method) {
      selector = new Selector.doInvoke(node.name);
    } else if (node.kind == ProcedureKind.Setter) {
      selector = new Selector.doSet(node.name);
    } else {
      return;
    }

    if (_selectors.dynamicSelectors.contains(selector)) {
      return;
    }

    final bool hasNonThisUses = _selectors.nonThisSelectors.contains(selector);
    final bool hasTearOffUses = _selectors.tearOffSelectors.contains(selector);
    ProcedureAttributesMetadata metadata;
    if (!hasNonThisUses && !hasTearOffUses) {
      metadata = const ProcedureAttributesMetadata(
          methodOrSetterCalledDynamically: false,
          getterCalledDynamically: false,
          hasNonThisUses: false,
          hasTearOffUses: false);
    } else if (!hasNonThisUses && hasTearOffUses) {
      metadata = const ProcedureAttributesMetadata(
          methodOrSetterCalledDynamically: false,
          getterCalledDynamically: false,
          hasNonThisUses: false,
          hasTearOffUses: true);
    } else if (hasNonThisUses && !hasTearOffUses) {
      metadata = const ProcedureAttributesMetadata(
          methodOrSetterCalledDynamically: false,
          getterCalledDynamically: false,
          hasNonThisUses: true,
          hasTearOffUses: false);
    } else {
      metadata = const ProcedureAttributesMetadata.noDynamicUses();
    }
    _metadata.mapping[node] = metadata;
  }
}

class DynamicSelectorsCollector extends RecursiveVisitor<Null> {
  final Set<Selector> dynamicSelectors = new Set<Selector>();
  final Set<Selector> nonThisSelectors = new Set<Selector>();
  final Set<Selector> tearOffSelectors = new Set<Selector>();

  static DynamicSelectorsCollector collect(Component component) {
    final v = new DynamicSelectorsCollector();
    v.visitComponent(component);

    // We only populate [nonThisSelectors] and [tearOffSelectors] inside the
    // non-dynamic case (for efficiency reasons) while visiting the [Component].
    //
    // After the recursive visit of [Component] we complete the sets here.
    for (final Selector selector in v.dynamicSelectors) {
      // All dynamic getters can be tearoffs.
      if (selector.action == Action.get) {
        v.tearOffSelectors.add(new Selector.doInvoke(selector.target));
      }

      // All dynamic selectors are non-this selectors.
      v.nonThisSelectors.add(selector);
    }

    return v;
  }

  @override
  visitMethodInvocation(MethodInvocation node) {
    super.visitMethodInvocation(node);

    Selector selector;
    if (node.interfaceTarget == null) {
      dynamicSelectors.add(new Selector.doInvoke(node.name));
    } else {
      if (node.receiver is! ThisExpression) {
        nonThisSelectors.add(selector ??= new Selector.doInvoke(node.name));
      }
    }
  }

  @override
  visitDirectMethodInvocation(DirectMethodInvocation node) {
    super.visitDirectMethodInvocation(node);

    Selector selector;
    if (node.receiver is! ThisExpression) {
      nonThisSelectors
          .add(selector ??= new Selector.doInvoke(node.target.name));
    }
  }

  @override
  visitPropertyGet(PropertyGet node) {
    super.visitPropertyGet(node);

    Selector selector;
    if (node.interfaceTarget == null) {
      dynamicSelectors.add(selector = new Selector.doGet(node.name));
    } else {
      if (node.receiver is! ThisExpression) {
        nonThisSelectors.add(selector ??= new Selector.doGet(node.name));
      }

      final target = node.interfaceTarget;
      if (target is Procedure && target.kind == ProcedureKind.Method) {
        tearOffSelectors.add(new Selector.doInvoke(node.name));
      }
    }
  }

  @override
  visitDirectPropertyGet(DirectPropertyGet node) {
    super.visitDirectPropertyGet(node);

    if (node.receiver is! ThisExpression) {
      nonThisSelectors.add(new Selector.doGet(node.target.name));
    }

    final target = node.target;
    if (target is Procedure && target.kind == ProcedureKind.Method) {
      tearOffSelectors.add(new Selector.doInvoke(target.name));
    }
  }

  @override
  visitPropertySet(PropertySet node) {
    super.visitPropertySet(node);

    Selector selector;
    if (node.interfaceTarget == null) {
      dynamicSelectors.add(selector = new Selector.doSet(node.name));
    } else {
      if (node.receiver is! ThisExpression) {
        nonThisSelectors.add(selector ??= new Selector.doSet(node.name));
      }
    }
  }

  @override
  visitDirectPropertySet(DirectPropertySet node) {
    super.visitDirectPropertySet(node);

    Selector selector;
    if (node.receiver is! ThisExpression) {
      nonThisSelectors.add(selector ??= new Selector.doSet(node.target.name));
    }
  }
}
