// Copyright (c) 2013, 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 js_backend;

/**
 * Support for Custom Elements.
 *
 * The support for custom elements the compiler builds a table that maps the
 * custom element class's [Type] to the interceptor for the class and the
 * constructor(s) for the class.
 *
 * We want the table to contain only the custom element classes used, and we
 * want to avoid resolving and compiling constructors that are not used since
 * that may bring in unused code.  This class controls the resolution and code
 * generation to restrict the impact.
 *
 * The following line of code requires the generation of the generative
 * constructor factory function(s) for FancyButton, and their insertion into the
 * table:
 *
 *     document.register(FancyButton, 'x-fancy-button');
 *
 * We detect this by 'joining' the classes that are referenced as type literals
 * with the classes that are custom elements, enabled by detecting the presence
 * of the table access code used by document.register.
 *
 * We have to be more conservative when the type is unknown, e.g.
 *
 *     document.register(classMirror.reflectedType, tagFromMetadata);
 *
 * and
 *
 *     class Component<T> {
 *       final tag;
 *       Component(this.tag);
 *       void register() => document.register(T, tag);
 *     }
 *     const Component<FancyButton>('x-fancy-button').register();
 *
 * In these cases we conservatively generate all viable entries in the table.
 */
class CustomElementsAnalysis {
  final JavaScriptBackend backend;
  final Compiler compiler;
  final CustomElementsAnalysisJoin resolutionJoin;
  final CustomElementsAnalysisJoin codegenJoin;
  bool fetchedTableAccessorMethod = false;
  Element tableAccessorMethod;

  CustomElementsAnalysis(JavaScriptBackend backend)
      : this.backend = backend,
        this.compiler = backend.compiler,
        resolutionJoin = new CustomElementsAnalysisJoin(backend),
        codegenJoin = new CustomElementsAnalysisJoin(backend) {
    // TODO(sra): Remove this work-around.  We should mark allClassesSelected in
    // both joins only when we see a construct generating an unknown [Type] but
    // we can't currently recognize all cases.  In particular, the work-around
    // for the unimplemented `ClassMirror.reflectedType` is not recognizable.
    // TODO(12607): Match on [ClassMirror.reflectedType]
    resolutionJoin.allClassesSelected = true;
    codegenJoin.allClassesSelected = true;
  }

  CustomElementsAnalysisJoin joinFor(Enqueuer enqueuer) =>
      enqueuer.isResolutionQueue ? resolutionJoin : codegenJoin;

  void registerInstantiatedClass(ClassElement classElement, Enqueuer enqueuer) {
    classElement.ensureResolved(compiler);
    if (!Elements.isNativeOrExtendsNative(classElement)) return;
    if (classElement.isMixinApplication) return;
    joinFor(enqueuer).instantiatedClasses.add(classElement);
  }

  void registerTypeLiteral(Element element, Enqueuer enqueuer) {
    // In codegen we see the TypeConstants instead.
    if (!enqueuer.isResolutionQueue) return;

    if (element.isClass()) {
      // TODO(sra): If we had a flow query from the type literal expression to
      // the Type argument of the metadata lookup, we could tell if this type
      // literal is really a demand for the metadata.
      resolutionJoin.selectedClasses.add(element);
    } else {
      // This is a type parameter of a parameterized class.
      // TODO(sra): Is there a way to determine which types are bound to the
      // parameter?
      resolutionJoin.allClassesSelected = true;
    }
  }

  void registerTypeConstant(Element element, Enqueuer enqueuer) {
    assert(element.isClass());
    assert(!enqueuer.isResolutionQueue);
    codegenJoin.selectedClasses.add(element);
  }

  void registerStaticUse(Element element, Enqueuer enqueuer) {
    assert(element != null);
    if (!fetchedTableAccessorMethod) {
      fetchedTableAccessorMethod = true;
      tableAccessorMethod = compiler.findInterceptor(
          'findIndexForWebComponentType');
    }
    if (element == tableAccessorMethod) {
      joinFor(enqueuer).demanded = true;
    }
  }

  void onQueueEmpty(Enqueuer enqueuer) {
    joinFor(enqueuer).flush(enqueuer);
  }

  bool get needsTable => codegenJoin.demanded;

  bool needsClass(ClassElement classElement) =>
      codegenJoin.activeClasses.contains(classElement);

  List<Element> constructors(ClassElement classElement) =>
      codegenJoin.escapingConstructors(classElement);
}


class CustomElementsAnalysisJoin {
  final JavaScriptBackend backend;
  Compiler get compiler => backend.compiler;

  // Classes that are candidates for needing constructors.  Classes are moved to
  // [activeClasses] when we know they need constructors.
  final instantiatedClasses = new Set<ClassElement>();

  // Classes explicitly named.
  final selectedClasses = new Set<ClassElement>();

  // True if we must conservatively include all extension classes.
  bool allClassesSelected = false;

  // Did we see a demand for the data?
  bool demanded = false;

  // ClassesOutput: classes requiring metadata.
  final activeClasses = new Set<ClassElement>();

  CustomElementsAnalysisJoin(this.backend);

  void flush(Enqueuer enqueuer) {
    if (!demanded) return;
    var newActiveClasses = new Set<ClassElement>();
    for (ClassElement classElement in instantiatedClasses) {
      bool isNative = classElement.isNative();
      bool isExtension =
          !isNative && Elements.isNativeOrExtendsNative(classElement);
      // Generate table entries for native classes that are explicitly named and
      // extensions that fix our criteria.
      if ((isNative && selectedClasses.contains(classElement)) ||
          (isExtension &&
              (allClassesSelected || selectedClasses.contains(classElement)))) {
        newActiveClasses.add(classElement);
        escapingConstructors(classElement).forEach(enqueuer.registerStaticUse);
        // Force the generaton of the type constant that is the key to an entry
        // in the generated table.
        Constant constant = makeTypeConstant(classElement);
        backend.registerCompileTimeConstant(
            constant, compiler.globalDependencies);
        compiler.constantHandler.addCompileTimeConstantForEmission(constant);
      }
    }
    activeClasses.addAll(newActiveClasses);
    instantiatedClasses.removeAll(newActiveClasses);
  }

  TypeConstant makeTypeConstant(ClassElement element) {
    DartType elementType = element.computeType(compiler).asRaw();
    DartType constantType = backend.typeImplementation.computeType(compiler);
    return new TypeConstant(elementType, constantType);
  }

  List<Element> escapingConstructors(ClassElement classElement) {
    List<Element> result = <Element>[];
    // Only classes that extend native classes have constructors in the table.
    // We could refine this to classes that extend Element, but that would break
    // the tests and there is no sane reason to subclass other native classes.
    if (classElement.isNative()) return result;

    selectGenerativeConstructors(ClassElement enclosing, Element member) {
      if (member.isGenerativeConstructor()) {
        // Ignore constructors that cannot be called with zero arguments.
        FunctionElement constructor = member;
        FunctionSignature parameters = constructor.computeSignature(compiler);
        if (parameters.requiredParameterCount == 0) {
          result.add(member);
        }
      }
    }
    classElement.forEachMember(selectGenerativeConstructors,
        includeBackendMembers: false,
        includeSuperAndInjectedMembers: false);
    return result;
  }
}
