// 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 dart2js.js_emitter;

class ClassEmitter extends CodeEmitterHelper {

  ClassStubGenerator get _stubGenerator =>
      new ClassStubGenerator(compiler, namer, backend);

  /**
   * Documentation wanted -- johnniwinther
   */
  void emitClass(Class cls, ClassBuilder enclosingBuilder) {
    ClassElement classElement = cls.element;

    assert(invariant(classElement, classElement.isDeclaration));

    emitter.needsClassSupport = true;

    ClassElement superclass = classElement.superclass;
    String superName = "";
    if (superclass != null) {
      superName = namer.getNameOfClass(superclass);
    }

    if (cls.isMixinApplication) {
      MixinApplication mixinApplication = cls;
      String mixinName = mixinApplication.mixinClass.name;
      superName = '$superName+$mixinName';
      emitter.needsMixinSupport = true;
    }

    ClassBuilder builder = new ClassBuilder(classElement, namer);
    builder.superName = superName;
    emitConstructorsForCSP(cls);
    emitFields(cls, builder);
    emitCheckedClassSetters(cls, builder);
    emitClassGettersSettersForCSP(cls, builder);
    emitInstanceMembers(cls, builder);
    emitCallStubs(cls, builder);
    emitRuntimeTypeInformation(cls, builder);
    emitNativeInfo(cls, builder);

    if (classElement == backend.closureClass) {
      // We add a special getter here to allow for tearing off a closure from
      // itself.
      String name = namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME);
      jsAst.Fun function = js('function() { return this; }');
      builder.addProperty(namer.getterNameFromAccessorName(name), function);
    }

    emitTypeVariableReaders(classElement, builder);

    emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder);
  }
  /**
  * Emits the precompiled constructor when in CSP mode.
  */
  void emitConstructorsForCSP(Class cls) {
    List<String> fieldNames = <String>[];

    if (!compiler.useContentSecurityPolicy) return;

    if (!cls.onlyForRti && !cls.isNative) {
      fieldNames = cls.fields.map((Field field) => field.name).toList();
    }

    ClassElement classElement = cls.element;

    jsAst.Expression constructorAst =
        _stubGenerator.generateClassConstructor(classElement, fieldNames);

    String constructorName = namer.getNameOfClass(classElement);
    OutputUnit outputUnit =
        compiler.deferredLoadTask.outputUnitForElement(classElement);
    emitter.emitPrecompiledConstructor(
        outputUnit, constructorName, constructorAst, fieldNames);
  }

  /// Returns `true` if fields added.
  bool emitFields(FieldContainer container,
                  ClassBuilder builder,
                  { bool classIsNative: false,
                    bool emitStatics: false }) {
    Iterable<Field> fields;
    if (container is Class) {
      if (emitStatics) {
        fields = container.staticFieldsForReflection;
      } else if (container.onlyForRti) {
        return false;
      } else {
        fields = container.fields;
      }
    } else {
      assert(container is Library);
      assert(emitStatics);
      fields = container.staticFieldsForReflection;
    }

    var fieldMetadata = [];
    bool hasMetadata = false;
    bool fieldsAdded = false;

    for (Field field in fields) {
      VariableElement fieldElement = field.element;
      String name = field.name;
      String accessorName = field.accessorName;
      bool needsGetter = field.needsGetter;
      bool needsSetter = field.needsUncheckedSetter;

        // Ignore needsCheckedSetter - that is handled below.
      bool needsAccessor = (needsGetter || needsSetter);
      // We need to output the fields for non-native classes so we can auto-
      // generate the constructor.  For native classes there are no
      // constructors, so we don't need the fields unless we are generating
      // accessors at runtime.
      bool needsFieldsForConstructor = !emitStatics && !classIsNative;
      if (needsFieldsForConstructor || needsAccessor) {
        var metadata =
            task.metadataCollector.buildMetadataFunction(fieldElement);
        if (metadata != null) {
          hasMetadata = true;
        } else {
          metadata = new jsAst.LiteralNull();
        }
        fieldMetadata.add(metadata);
        recordMangledField(fieldElement, accessorName,
            namer.privateName(fieldElement.library, fieldElement.name));
        String fieldName = name;
        String fieldCode = '';
        String reflectionMarker = '';
        if (!needsAccessor) {
          // Emit field for constructor generation.
          assert(!classIsNative);
        } else {
          // Emit (possibly renaming) field name so we can add accessors at
          // runtime.
          if (name != accessorName) {
            fieldName = '$accessorName:$name';
          }

          if (field.needsInterceptedGetter) {
            emitter.interceptorEmitter.interceptorInvocationNames.add(
                namer.getterName(fieldElement));
          }
          // TODO(16168): The setter creator only looks at the getter-name.
          // Even though the setter could avoid the interceptor convention we
          // currently still need to add the additional argument.
          if (field.needsInterceptedGetter || field.needsInterceptedSetter) {
            emitter.interceptorEmitter.interceptorInvocationNames.add(
                namer.setterName(fieldElement));
          }

          int code = field.getterFlags + (field.setterFlags << 2);
          if (code == 0) {
            compiler.internalError(fieldElement,
                'Field code is 0 ($fieldElement).');
          } else {
            fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE];
          }
        }
        if (backend.isAccessibleByReflection(fieldElement)) {
          DartType type = fieldElement.type;
          reflectionMarker = '-${task.metadataCollector.reifyType(type)}';
        }
        String builtFieldname = '$fieldName$fieldCode$reflectionMarker';
        builder.addField(builtFieldname);
        // Add 1 because adding a field to the class also requires a comma
        compiler.dumpInfoTask.recordFieldNameSize(fieldElement,
            builtFieldname.length + 1);
        fieldsAdded = true;
      }
    }

    if (hasMetadata) {
      builder.fieldMetadata = fieldMetadata;
    }
    return fieldsAdded;
  }

  /// Emits checked setters for fields.
  void emitCheckedClassSetters(Class cls, ClassBuilder builder) {
    if (cls.onlyForRti) return;

    for (Field field in cls.fields) {
      if (field.needsCheckedSetter) {
        assert(!field.needsUncheckedSetter);
        compiler.withCurrentElement(field.element, () {
          generateCheckedSetter(
              field.element, field.name, field.accessorName, builder);
        });
      }
    }
  }

  /// Emits getters/setters for fields if compiling in CSP mode.
  void emitClassGettersSettersForCSP(Class cls, ClassBuilder builder) {

    if (!compiler.useContentSecurityPolicy || cls.onlyForRti) return;

    for (Field field in cls.fields) {
      Element member = field.element;
      compiler.withCurrentElement(member, () {
        if (field.needsGetter) {
          emitGetterForCSP(member, field.name, field.accessorName, builder);
        }
        if (field.needsUncheckedSetter) {
          emitSetterForCSP(member, field.name, field.accessorName, builder);
        }
      });
    }
  }

  void emitCallStubs(Class cls, ClassBuilder builder) {
    for (Method method in cls.callStubs) {
      jsAst.Property property = builder.addProperty(method.name, method.code);
      compiler.dumpInfoTask.registerElementAst(method.element, property);
    }
  }

  /**
   * Documentation wanted -- johnniwinther
   *
   * Invariant: [classElement] must be a declaration element.
   */
  void emitInstanceMembers(Class cls,
                           ClassBuilder builder) {
    ClassElement classElement = cls.element;
    assert(invariant(classElement, classElement.isDeclaration));

    if (cls.onlyForRti || cls.isMixinApplication) return;

    // TODO(herhut): This is a no-op. Should it be removed?
    for (Field field in cls.fields) {
      emitter.containerBuilder.addMemberField(field, builder);
    }

    for (Method method in cls.methods) {
      assert(invariant(classElement, method.element.isDeclaration));
      assert(invariant(classElement, method.element.isInstanceMember));
      emitter.containerBuilder.addMemberMethod(method, builder);
    }

    if (identical(classElement, compiler.objectClass)
        && compiler.enabledNoSuchMethod) {
      // Emit the noSuchMethod handlers on the Object prototype now,
      // so that the code in the dynamicFunction helper can find
      // them. Note that this helper is invoked before analyzing the
      // full JS script.
      if (!emitter.nativeEmitter.handleNoSuchMethod) {
        emitter.nsmEmitter.emitNoSuchMethodHandlers(builder.addProperty);
      }
    }
  }

  /// Emits the members from the model.
  void emitRuntimeTypeInformation(Class cls, ClassBuilder builder) {
    assert(builder.functionType == null);
    if (cls.functionTypeIndex != null) {
      builder.functionType = '${cls.functionTypeIndex}';
    }

    for (Method method in cls.isChecks) {
      builder.addProperty(method.name, method.code);
    }
  }

  void emitNativeInfo(Class cls, ClassBuilder builder) {
    if (cls.nativeInfo != null) {
      builder.addProperty(namer.nativeSpecProperty, js.string(cls.nativeInfo));
    }
  }

  void emitClassBuilderWithReflectionData(Class cls,
                                          ClassBuilder classBuilder,
                                          ClassBuilder enclosingBuilder) {
    ClassElement classElement = cls.element;
    String className = cls.name;

    var metadata = task.metadataCollector.buildMetadataFunction(classElement);
    if (metadata != null) {
      classBuilder.addProperty("@", metadata);
    }

    if (backend.isAccessibleByReflection(classElement)) {
      List<DartType> typeVars = classElement.typeVariables;
      Iterable typeVariableProperties = emitter.typeVariableHandler
          .typeVariablesOf(classElement).map(js.number);

      ClassElement superclass = classElement.superclass;
      bool hasSuper = superclass != null;
      if ((!typeVariableProperties.isEmpty && !hasSuper) ||
          (hasSuper && !equalElements(superclass.typeVariables, typeVars))) {
        classBuilder.addProperty('<>',
            new jsAst.ArrayInitializer(typeVariableProperties.toList()));
      }
    }

    List<jsAst.Property> statics = new List<jsAst.Property>();
    ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer);
    if (emitFields(cls, staticsBuilder, emitStatics: true)) {
      jsAst.ObjectInitializer initializer =
        staticsBuilder.toObjectInitializer();
      compiler.dumpInfoTask.registerElementAst(classElement,
        initializer);
      jsAst.Node property = initializer.properties.single;
      compiler.dumpInfoTask.registerElementAst(classElement, property);
      statics.add(property);
    }

    ClassBuilder classProperties =
        emitter.elementDescriptors.remove(classElement);
    if (classProperties != null) {
      statics.addAll(classProperties.properties);
    }

    if (!statics.isEmpty) {
      classBuilder.addProperty('static', new jsAst.ObjectInitializer(statics));
    }

    // TODO(ahe): This method (generateClass) should return a jsAst.Expression.
    jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer();
    compiler.dumpInfoTask.registerElementAst(classBuilder.element, propertyValue);
    enclosingBuilder.addProperty(className, propertyValue);

    String reflectionName = emitter.getReflectionName(classElement, className);
    if (reflectionName != null) {
      if (!backend.isAccessibleByReflection(classElement)) {
        enclosingBuilder.addProperty("+$reflectionName", js.number(0));
      } else {
        List<int> types = <int>[];
        if (classElement.supertype != null) {
          types.add(task.metadataCollector.reifyType(classElement.supertype));
        }
        for (DartType interface in classElement.interfaces) {
          types.add(task.metadataCollector.reifyType(interface));
        }
        enclosingBuilder.addProperty("+$reflectionName",
            new jsAst.ArrayInitializer(types.map(js.number).toList()));
      }
    }
  }

  /**
   * Invokes [f] for each of the fields of [element].
   *
   * [element] must be a [ClassElement] or a [LibraryElement].
   *
   * If [element] is a [ClassElement], the static fields of the class are
   * visited if [visitStatics] is true and the instance fields are visited if
   * [visitStatics] is false.
   *
   * If [element] is a [LibraryElement], [visitStatics] must be true.
   *
   * When visiting the instance fields of a class, the fields of its superclass
   * are also visited if the class is instantiated.
   *
   * Invariant: [element] must be a declaration element.
   */
  void visitFields(Element element, bool visitStatics, AcceptField f) {
    assert(invariant(element, element.isDeclaration));

    bool isClass = false;
    bool isLibrary = false;
    if (element.isClass) {
      isClass = true;
    } else if (element.isLibrary) {
      isLibrary = true;
      assert(invariant(element, visitStatics));
    } else {
      throw new SpannableAssertionFailure(
          element, 'Expected a ClassElement or a LibraryElement.');
    }

    // If the class is never instantiated we still need to set it up for
    // inheritance purposes, but we can simplify its JavaScript constructor.
    bool isInstantiated =
        compiler.codegenWorld.directlyInstantiatedClasses.contains(element);

    void visitField(Element holder, VariableElement field) {
      assert(invariant(element, field.isDeclaration));
      String name = field.name;

      // Keep track of whether or not we're dealing with a field mixin
      // into a native class.
      bool isMixinNativeField =
          isClass && element.isNative && holder.isMixinApplication;

      // See if we can dynamically create getters and setters.
      // We can only generate getters and setters for [element] since
      // the fields of super classes could be overwritten with getters or
      // setters.
      bool needsGetter = false;
      bool needsSetter = false;
      if (isLibrary || isMixinNativeField || holder == element) {
        needsGetter = fieldNeedsGetter(field);
        needsSetter = fieldNeedsSetter(field);
      }

      if ((isInstantiated && !holder.isNative)
          || needsGetter
          || needsSetter) {
        String accessorName = namer.fieldAccessorName(field);
        String fieldName = namer.fieldPropertyName(field);
        bool needsCheckedSetter = false;
        if (compiler.enableTypeAssertions
            && needsSetter
            && !canAvoidGeneratedCheckedSetter(field)) {
          needsCheckedSetter = true;
          needsSetter = false;
        }
        // Getters and setters with suffixes will be generated dynamically.
        f(field, fieldName, accessorName, needsGetter, needsSetter,
          needsCheckedSetter);
      }
    }

    if (isLibrary) {
      LibraryElement library = element;
      library.implementation.forEachLocalMember((Element member) {
        if (member.isField) visitField(library, member);
      });
    } else if (visitStatics) {
      ClassElement cls = element;
      cls.implementation.forEachStaticField(visitField);
    } else {
      ClassElement cls = element;
      // TODO(kasperl): We should make sure to only emit one version of
      // overridden fields. Right now, we rely on the ordering so the
      // fields pulled in from mixins are replaced with the fields from
      // the class definition.

      // If a class is not instantiated then we add the field just so we can
      // generate the field getter/setter dynamically. Since this is only
      // allowed on fields that are in [element] we don't need to visit
      // superclasses for non-instantiated classes.
      cls.implementation.forEachInstanceField(
          visitField, includeSuperAndInjectedMembers: isInstantiated);
    }
  }

  void recordMangledField(Element member,
                          String accessorName,
                          String memberName) {
    if (!backend.shouldRetainGetter(member)) return;
    String previousName;
    if (member.isInstanceMember) {
      previousName = emitter.mangledFieldNames.putIfAbsent(
          '${namer.getterPrefix}$accessorName',
          () => memberName);
    } else {
      previousName = emitter.mangledGlobalFieldNames.putIfAbsent(
          accessorName,
          () => memberName);
    }
    assert(invariant(member, previousName == memberName,
                     message: '$previousName != ${memberName}'));
  }

  bool fieldNeedsGetter(VariableElement field) {
    assert(field.isField);
    if (fieldAccessNeverThrows(field)) return false;
    return backend.shouldRetainGetter(field)
        || compiler.codegenWorld.hasInvokedGetter(field, compiler.world);
  }

  bool fieldNeedsSetter(VariableElement field) {
    assert(field.isField);
    if (fieldAccessNeverThrows(field)) return false;
    return (!field.isFinal && !field.isConst)
        && (backend.shouldRetainSetter(field)
            || compiler.codegenWorld.hasInvokedSetter(field, compiler.world));
  }

  // We never access a field in a closure (a captured variable) without knowing
  // that it is there.  Therefore we don't need to use a getter (that will throw
  // if the getter method is missing), but can always access the field directly.
  static bool fieldAccessNeverThrows(VariableElement field) {
    return field is ClosureFieldElement;
  }

  bool canAvoidGeneratedCheckedSetter(VariableElement member) {
    // We never generate accessors for top-level/static fields.
    if (!member.isInstanceMember) return true;
    DartType type = member.type;
    return type.treatAsDynamic || (type.element == compiler.objectClass);
  }

  void generateCheckedSetter(Element member,
                             String fieldName,
                             String accessorName,
                             ClassBuilder builder) {
    jsAst.Expression code = backend.generatedCode[member];
    assert(code != null);
    String setterName = namer.setterNameFromAccessorName(accessorName);
    compiler.dumpInfoTask.registerElementAst(member,
        builder.addProperty(setterName, code));
    generateReflectionDataForFieldGetterOrSetter(
        member, setterName, builder, isGetter: false);
  }

  void emitGetterForCSP(Element member, String fieldName, String accessorName,
                        ClassBuilder builder) {
    jsAst.Expression function =
        _stubGenerator.generateGetter(member, fieldName);

    String getterName = namer.getterNameFromAccessorName(accessorName);
    ClassElement cls = member.enclosingClass;
    String className = namer.getNameOfClass(cls);
    OutputUnit outputUnit =
        compiler.deferredLoadTask.outputUnitForElement(member);
    emitter.cspPrecompiledFunctionFor(outputUnit).add(
        js('#.prototype.# = #', [className, getterName, function]));
    if (backend.isAccessibleByReflection(member)) {
      emitter.cspPrecompiledFunctionFor(outputUnit).add(
          js('#.prototype.#.${namer.reflectableField} = 1',
              [className, getterName]));
    }
  }

  void emitSetterForCSP(Element member, String fieldName, String accessorName,
                        ClassBuilder builder) {
    jsAst.Expression function =
        _stubGenerator.generateSetter(member, fieldName);

    String setterName = namer.setterNameFromAccessorName(accessorName);
    ClassElement cls = member.enclosingClass;
    String className = namer.getNameOfClass(cls);
    OutputUnit outputUnit =
        compiler.deferredLoadTask.outputUnitForElement(member);
    emitter.cspPrecompiledFunctionFor(outputUnit).add(
        js('#.prototype.# = #', [className, setterName, function]));
    if (backend.isAccessibleByReflection(member)) {
      emitter.cspPrecompiledFunctionFor(outputUnit).add(
          js('#.prototype.#.${namer.reflectableField} = 1',
              [className, setterName]));
    }
  }

  void generateReflectionDataForFieldGetterOrSetter(Element member,
                                                    String name,
                                                    ClassBuilder builder,
                                                    {bool isGetter}) {
    Selector selector = isGetter
        ? new Selector.getter(member.name, member.library)
        : new Selector.setter(member.name, member.library);
    String reflectionName = emitter.getReflectionName(selector, name);
    if (reflectionName != null) {
      var reflectable =
          js(backend.isAccessibleByReflection(member) ? '1' : '0');
      builder.addProperty('+$reflectionName', reflectable);
    }
  }

  void emitTypeVariableReaders(ClassElement cls, ClassBuilder builder) {
    List typeVariables = [];
    ClassElement superclass = cls;
    while (superclass != null) {
      for (TypeVariableType parameter in superclass.typeVariables) {
        if (backend.emitter.readTypeVariables.contains(parameter.element)) {
          emitTypeVariableReader(cls, builder, parameter.element);
        }
      }
      superclass = superclass.superclass;
    }
  }

  void emitTypeVariableReader(ClassElement cls,
                              ClassBuilder builder,
                              TypeVariableElement element) {
    String name = namer.readTypeVariableName(element);
    int index = RuntimeTypes.getTypeVariableIndex(element);
    jsAst.Expression computeTypeVariable;

    Substitution substitution =
        backend.rti.computeSubstitution(
            cls, element.typeDeclaration, alwaysGenerateFunction: true);
    if (substitution != null) {
      computeTypeVariable =
          js(r'#.apply(null, this.$builtinTypeInfo)',
             substitution.getCodeForVariable(index, backend.rti));
    } else {
      // TODO(ahe): These can be generated dynamically.
      computeTypeVariable =
          js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]',
              js.number(index));
    }
    jsAst.Expression convertRtiToRuntimeType = emitter
        .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType'));
    compiler.dumpInfoTask.registerElementAst(element,
        builder.addProperty(name,
            js('function () { return #(#) }',
                [convertRtiToRuntimeType, computeTypeVariable])));
  }
}
