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

library dart2js.mirrors_handler;

import '../common.dart';
import '../common/resolution.dart';
import '../compiler.dart';
import '../constants/values.dart';
import '../diagnostics/diagnostic_listener.dart';
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../enqueue.dart';
import '../universe/selector.dart';
import '../universe/use.dart';
import '../universe/world_impact.dart';
import 'backend.dart';
import 'constant_handler_javascript.dart';
import 'mirrors_data.dart';

abstract class MirrorsResolutionAnalysis {
  void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses);

  void onResolutionComplete();

  /// Close this analysis and create the [MirrorsCodegenAnalysis] for the
  /// collected data.
  MirrorsCodegenAnalysis close();
}

abstract class MirrorsCodegenAnalysis {
  void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses);

  /// Number of methods compiled before considering reflection.
  int get preMirrorsMethodCount;
}

class MirrorsResolutionAnalysisImpl implements MirrorsResolutionAnalysis {
  final JavaScriptBackend _backend;
  final MirrorsHandler handler;

  /// Set of elements for which metadata has been registered as dependencies.
  final Set<Element> _registeredMetadata = new Set<Element>();

  /// List of constants from metadata.  If metadata must be preserved,
  /// these constants must be registered.
  final List<Dependency> _metadataConstants = <Dependency>[];

  StagedWorldImpactBuilder _impactBuilder = new StagedWorldImpactBuilder();

  MirrorsResolutionAnalysisImpl(this._backend, Resolution resolution)
      : handler = new MirrorsHandler(_backend, resolution);

  DiagnosticReporter get _reporter => _backend.reporter;
  Compiler get _compiler => _backend.compiler;
  JavaScriptConstantCompiler get _constants => _backend.constants;
  MirrorsData get _mirrorsData => _backend.mirrorsData;

  /// Returns all static fields that are referenced through
  /// `mirrorsData.targetsUsed`. If the target is a library or class all nested
  /// static fields are included too.
  Iterable<Element> _findStaticFieldTargets() {
    List<Element> staticFields = <Element>[];

    void addFieldsInContainer(ScopeContainerElement container) {
      container.forEachLocalMember((Element member) {
        if (!member.isInstanceMember && member.isField) {
          staticFields.add(member);
        } else if (member.isClass) {
          addFieldsInContainer(member);
        }
      });
    }

    for (MemberElement target in _mirrorsData.membersInMirrorsUsedTargets) {
      if (target.isField) {
        staticFields.add(target);
      }
    }
    for (ClassElement target in _mirrorsData.classesInMirrorsUsedTargets) {
      addFieldsInContainer(target);
    }
    for (LibraryElement target in _mirrorsData.librariesInMirrorsUsedTargets) {
      addFieldsInContainer(target);
    }
    return staticFields;
  }

  /// Compute the impact for elements that are matched by the mirrors used
  /// annotation or, in lack thereof, all elements.
  WorldImpact _computeImpactForReflectiveElements(
      Iterable<ClassEntity> recents,
      Iterable<ClassEntity> processedClasses,
      Iterable<LibraryElement> loadedLibraries) {
    handler.enqueueReflectiveElements(
        recents, processedClasses, loadedLibraries);
    return handler.flush();
  }

  /// Compute the impact for the static fields that have been marked as used by
  /// reflective usage through `MirrorsUsed`.
  WorldImpact _computeImpactForReflectiveStaticFields(
      Iterable<Element> elements) {
    handler.enqueueReflectiveStaticFields(elements);
    return handler.flush();
  }

  void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses) {
    if (_mirrorsData.isTreeShakingDisabled) {
      enqueuer.applyImpact(_computeImpactForReflectiveElements(recentClasses,
          enqueuer.processedClasses, _compiler.libraryLoader.libraries));
    } else if (_mirrorsData.membersInMirrorsUsedTargets.isNotEmpty ||
        _mirrorsData.classesInMirrorsUsedTargets.isNotEmpty ||
        _mirrorsData.librariesInMirrorsUsedTargets.isNotEmpty) {
      // Add all static elements (not classes) that have been requested for
      // reflection. If there is no mirror-usage these are probably not
      // necessary, but the backend relies on them being resolved.
      enqueuer.applyImpact(
          _computeImpactForReflectiveStaticFields(_findStaticFieldTargets()));
    }

    if (_mirrorsData.mustPreserveNames) _reporter.log('Preserving names.');

    if (_mirrorsData.mustRetainMetadata) {
      _reporter.log('Retaining metadata.');

      for (LibraryEntity library in _compiler.libraryLoader.libraries) {
        _mirrorsData.retainMetadataOfLibrary(library,
            addForEmission: !enqueuer.isResolutionQueue);
      }

      if (!enqueuer.queueIsClosed) {
        /// Register the constant value of [metadata] as live in resolution.
        void registerMetadataConstant(MetadataAnnotation metadata) {
          ConstantValue constant =
              _constants.getConstantValueForMetadata(metadata);
          Dependency dependency =
              new Dependency(constant, metadata.annotatedElement);
          _metadataConstants.add(dependency);
          _impactBuilder.registerConstantUse(new ConstantUse.mirrors(constant));
        }

        // TODO(johnniwinther): We should have access to all recently processed
        // elements and process these instead.
        processMetadata(enqueuer.processedEntities, registerMetadataConstant);
      } else {
        for (Dependency dependency in _metadataConstants) {
          _impactBuilder.registerConstantUse(
              new ConstantUse.mirrors(dependency.constant));
        }
        _metadataConstants.clear();
      }
      enqueuer.applyImpact(_impactBuilder.flush());
    }
  }

  /// Call [registerMetadataConstant] on all metadata from [entities].
  void processMetadata(
      Iterable<Entity> entities, void onMetadata(MetadataAnnotation metadata)) {
    void processLibraryMetadata(LibraryElement library) {
      if (_registeredMetadata.add(library)) {
        library.metadata.forEach(onMetadata);
        library.entryCompilationUnit.metadata.forEach(onMetadata);
        for (ImportElement import in library.imports) {
          import.metadata.forEach(onMetadata);
        }
      }
    }

    void processElementMetadata(Element element) {
      if (_registeredMetadata.add(element)) {
        element.metadata.forEach(onMetadata);
        if (element.isFunction) {
          FunctionElement function = element;
          for (ParameterElement parameter in function.parameters) {
            parameter.metadata.forEach(onMetadata);
          }
        }
        if (element.enclosingClass != null) {
          // Only process library of top level fields/methods
          // (and not for classes).
          // TODO(johnniwinther): Fix this: We are missing some metadata on
          // libraries (example: in co19/Language/Metadata/before_export_t01).
          if (element.enclosingElement is ClassElement) {
            // Use [enclosingElement] instead of [enclosingClass] to ensure that
            // we process patch class metadata for patch and injected members.
            processElementMetadata(element.enclosingElement);
          }
        } else {
          processLibraryMetadata(element.library);
        }
      }
    }

    entities.forEach((member) => processElementMetadata(member));
  }

  void onResolutionComplete() {
    _registeredMetadata.clear();
  }

  MirrorsCodegenAnalysis close() => new MirrorsCodegenAnalysisImpl(
      _backend, handler._resolution, _metadataConstants);
}

class MirrorsCodegenAnalysisImpl implements MirrorsCodegenAnalysis {
  final JavaScriptBackend _backend;
  final MirrorsHandler handler;

  StagedWorldImpactBuilder _impactBuilder = new StagedWorldImpactBuilder();

  /// List of constants from metadata.  If metadata must be preserved,
  /// these constants must be registered.
  final List<Dependency> _metadataConstants;

  /// Number of methods compiled before considering reflection.
  int preMirrorsMethodCount = 0;

  MirrorsCodegenAnalysisImpl(
      this._backend, Resolution resolution, this._metadataConstants)
      : handler = new MirrorsHandler(_backend, resolution);

  DiagnosticReporter get _reporter => _backend.reporter;
  Compiler get _compiler => _backend.compiler;
  JavaScriptConstantCompiler get _constants => _backend.constants;
  MirrorsData get _mirrorsData => _backend.mirrorsData;

  /// Compute the impact for elements that are matched by the mirrors used
  /// annotation or, in lack thereof, all elements.
  WorldImpact _computeImpactForReflectiveElements(
      Iterable<ClassEntity> recents,
      Iterable<ClassEntity> processedClasses,
      Iterable<LibraryElement> loadedLibraries) {
    handler.enqueueReflectiveElements(
        recents, processedClasses, loadedLibraries);
    return handler.flush();
  }

  void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses) {
    if (preMirrorsMethodCount == 0) {
      preMirrorsMethodCount = _backend.generatedCode.length;
    }
    if (_mirrorsData.isTreeShakingDisabled) {
      enqueuer.applyImpact(_computeImpactForReflectiveElements(recentClasses,
          enqueuer.processedClasses, _compiler.libraryLoader.libraries));
    }

    if (_mirrorsData.mustPreserveNames) _reporter.log('Preserving names.');

    if (_mirrorsData.mustRetainMetadata) {
      _reporter.log('Retaining metadata.');

      (_compiler.libraryLoader.libraries as Iterable<LibraryElement>)
          .forEach(_mirrorsData.retainMetadataOfLibrary);

      for (Dependency dependency in _metadataConstants) {
        _impactBuilder
            .registerConstantUse(new ConstantUse.mirrors(dependency.constant));
      }
      _metadataConstants.clear();
      enqueuer.applyImpact(_impactBuilder.flush());
    }
  }
}

class MirrorsHandler {
  static final TRACE_MIRROR_ENQUEUING =
      const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING");

  final JavaScriptBackend _backend;
  final Resolution _resolution;

  bool hasEnqueuedReflectiveElements = false;
  bool hasEnqueuedReflectiveStaticFields = false;

  StagedWorldImpactBuilder impactBuilder = new StagedWorldImpactBuilder();

  MirrorsHandler(this._backend, this._resolution);

  DiagnosticReporter get _reporter => _resolution.reporter;

  WorldImpact flush() => impactBuilder.flush();

  void _logEnqueueReflectiveAction(action, [msg = ""]) {
    if (TRACE_MIRROR_ENQUEUING) {
      print("MIRROR_ENQUEUE (R): $action $msg");
    }
  }

  /**
   * Decides whether an element should be included to satisfy requirements
   * of the mirror system.
   *
   * During resolution, we have to resort to matching elements against the
   * [MirrorsUsed] pattern, as we do not have a complete picture of the world,
   * yet.
   */
  bool _shouldIncludeLibraryDueToMirrors(LibraryElement element,
      {bool includedEnclosing}) {
    return includedEnclosing ||
        _backend.mirrorsData.isLibraryRequiredByMirrorSystem(element);
  }

  bool _shouldIncludeClassDueToMirrors(ClassElement element,
      {bool includedEnclosing}) {
    return includedEnclosing ||
        _backend.mirrorsData.isClassRequiredByMirrorSystem(element);
  }

  bool _shouldIncludeMemberDueToMirrors(MemberElement element,
      {bool includedEnclosing}) {
    return includedEnclosing ||
        _backend.mirrorsData.isMemberRequiredByMirrorSystem(element);
  }

  /// Enqueue the constructor [ctor] if it is required for reflection.
  ///
  /// [enclosingWasIncluded] provides a hint whether the enclosing element was
  /// needed for reflection.
  void _enqueueReflectiveConstructor(ConstructorElement constructor,
      {bool enclosingWasIncluded}) {
    assert(constructor.isDeclaration);
    if (_shouldIncludeMemberDueToMirrors(constructor,
        includedEnclosing: enclosingWasIncluded)) {
      if (constructor.isFromEnvironmentConstructor) return;
      _logEnqueueReflectiveAction(constructor);
      ClassElement cls = constructor.enclosingClass;
      impactBuilder
          .registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType));
      impactBuilder.registerStaticUse(new StaticUse.mirrorUse(constructor));
    }
  }

  /// Enqueue the member [element] if it is required for reflection.
  ///
  /// [enclosingWasIncluded] provides a hint whether the enclosing element was
  /// needed for reflection.
  void _enqueueReflectiveMember(
      MemberElement element, bool enclosingWasIncluded) {
    assert(element.isDeclaration);
    if (_shouldIncludeMemberDueToMirrors(element,
        includedEnclosing: enclosingWasIncluded)) {
      _logEnqueueReflectiveAction(element);
      if (Elements.isStaticOrTopLevel(element)) {
        impactBuilder.registerStaticUse(new StaticUse.mirrorUse(element));
      } else if (element.isInstanceMember) {
        // We need to enqueue all members matching this one in subclasses, as
        // well.
        // TODO(herhut): Use TypedSelector.subtype for enqueueing
        DynamicUse dynamicUse =
            new DynamicUse(new Selector.fromElement(element));
        impactBuilder.registerDynamicUse(dynamicUse);
        if (element.isField) {
          DynamicUse dynamicUse =
              new DynamicUse(new Selector.setter(element.memberName.setter));
          impactBuilder.registerDynamicUse(dynamicUse);
        }
      }
    }
  }

  /// Enqueue the member [element] if it is required for reflection.
  ///
  /// [enclosingWasIncluded] provides a hint whether the enclosing element was
  /// needed for reflection.
  void _enqueueReflectiveElementsInClass(
      ClassElement cls, Iterable<ClassEntity> recents,
      {bool enclosingWasIncluded}) {
    assert(cls.isDeclaration);
    if (cls.library.isInternalLibrary || cls.isInjected) return;
    bool includeClass = _shouldIncludeClassDueToMirrors(cls,
        includedEnclosing: enclosingWasIncluded);
    if (includeClass) {
      _logEnqueueReflectiveAction(cls, "register");
      ClassElement declaration = cls.declaration;
      declaration.ensureResolved(_resolution);
      impactBuilder.registerTypeUse(
          new TypeUse.mirrorInstantiation(declaration.rawType));
    }
    // If the class is never instantiated, we know nothing of it can possibly
    // be reflected upon.
    // TODO(herhut): Add a warning if a mirrors annotation cannot hit.
    if (recents.contains(cls.declaration)) {
      _logEnqueueReflectiveAction(cls, "members");
      cls.constructors.forEach((Element element) {
        _enqueueReflectiveConstructor(element.declaration,
            enclosingWasIncluded: includeClass);
      });
      cls.forEachClassMember((Member member) {
        _enqueueReflectiveMember(member.element, includeClass);
      });
    }
  }

  /// Set of classes that need to be considered for reflection although not
  /// otherwise visible during resolution.
  Iterable<ClassEntity> get _classesRequiredForReflection {
    // TODO(herhut): Clean this up when classes needed for rti are tracked.
    return [
      _resolution.commonElements.closureClass,
      _resolution.commonElements.jsIndexableClass
    ];
  }

  /// Enqueue special classes that might not be visible by normal means or that
  /// would not normally be enqueued:
  ///
  /// [Closure] is treated specially as it is the superclass of all closures.
  /// Although it is in an internal library, we mark it as reflectable. Note
  /// that none of its methods are reflectable, unless reflectable by
  /// inheritance.
  void _enqueueReflectiveSpecialClasses() {
    Iterable<ClassElement> classes = _classesRequiredForReflection;
    for (ClassElement cls in classes) {
      if (_backend.mirrorsData.isClassReferencedFromMirrorSystem(cls)) {
        _logEnqueueReflectiveAction(cls);
        cls.ensureResolved(_resolution);
        impactBuilder
            .registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType));
      }
    }
  }

  /// Enqueue all local members of the library [lib] if they are required for
  /// reflection.
  void _enqueueReflectiveElementsInLibrary(
      LibraryElement lib, Iterable<ClassEntity> recents) {
    assert(lib.isDeclaration);
    bool includeLibrary =
        _shouldIncludeLibraryDueToMirrors(lib, includedEnclosing: false);
    lib.forEachLocalMember((Element member) {
      if (member.isInjected) return;
      if (member.isClass) {
        ClassElement cls = member;
        cls.ensureResolved(_resolution);
        do {
          _enqueueReflectiveElementsInClass(cls, recents,
              enclosingWasIncluded: includeLibrary);
          cls = cls.superclass;
        } while (cls != null && cls.isUnnamedMixinApplication);
      } else if (member.isTypedef) {
        TypedefElement typedef = member;
        typedef.ensureResolved(_resolution);
      } else {
        _enqueueReflectiveMember(member, includeLibrary);
      }
    });
  }

  /// Enqueue all elements that are matched by the mirrors used
  /// annotation or, in lack thereof, all elements.
  // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly.
  void enqueueReflectiveElements(
      Iterable<ClassEntity> recents,
      Iterable<ClassEntity> processedClasses,
      Iterable<LibraryElement> loadedLibraries) {
    if (!hasEnqueuedReflectiveElements) {
      _logEnqueueReflectiveAction("!START enqueueAll");
      // First round of enqueuing, visit everything that is visible to
      // also pick up static top levels, etc.
      // Also, during the first round, consider all classes that have been seen
      // as recently seen, as we do not know how many rounds of resolution might
      // have run before tree shaking is disabled and thus everything is
      // enqueued.
      recents = processedClasses.toSet();
      _reporter.log('Enqueuing everything');
      for (LibraryElement lib in loadedLibraries) {
        _enqueueReflectiveElementsInLibrary(lib, recents);
      }
      _enqueueReflectiveSpecialClasses();
      hasEnqueuedReflectiveElements = true;
      hasEnqueuedReflectiveStaticFields = true;
      _logEnqueueReflectiveAction("!DONE enqueueAll");
    } else if (recents.isNotEmpty) {
      // Keep looking at new classes until fixpoint is reached.
      _logEnqueueReflectiveAction("!START enqueueRecents");
      recents.forEach((ClassEntity _cls) {
        ClassElement cls = _cls;
        _enqueueReflectiveElementsInClass(cls, recents,
            enclosingWasIncluded: _shouldIncludeLibraryDueToMirrors(cls.library,
                includedEnclosing: false));
      });
      _logEnqueueReflectiveAction("!DONE enqueueRecents");
    }
  }

  /// Enqueue the static fields that have been marked as used by reflective
  /// usage through `MirrorsUsed`.
  // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly.
  void enqueueReflectiveStaticFields(Iterable<Element> elements) {
    if (hasEnqueuedReflectiveStaticFields) return;
    hasEnqueuedReflectiveStaticFields = true;
    for (Element element in elements) {
      _enqueueReflectiveMember(element, true);
    }
  }
}

/// Records that [constant] is used by the element behind [registry].
class Dependency {
  final ConstantValue constant;
  final Element annotatedElement;

  const Dependency(this.constant, this.annotatedElement);

  String toString() => '$annotatedElement:${constant.toStructuredText()}';
}
