// 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), null);
        impactBuilder.registerDynamicUse(dynamicUse);
        if (element.isField) {
          DynamicUse dynamicUse = new DynamicUse(
              new Selector.setter(element.memberName.setter), null);
          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()}';
}
