/*
 * Copyright 2015 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.dev.jjs.impl;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.MinimalRebuildCache;
import com.google.gwt.dev.javac.JsInteropUtil;
import com.google.gwt.dev.jjs.HasSourceInfo;
import com.google.gwt.dev.jjs.ast.CanBeJsNative;
import com.google.gwt.dev.jjs.ast.CanHaveSuppressedWarnings;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.HasJsInfo.JsMemberType;
import com.google.gwt.dev.jjs.ast.HasJsName;
import com.google.gwt.dev.jjs.ast.HasType;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConstructor;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JDeclaredType.NestedClassDisposition;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JExpressionStatement;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JInstanceOf;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JMember;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JPrimitiveType;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JStatement;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
import com.google.gwt.dev.js.JsUtils;
import com.google.gwt.dev.js.ast.JsContext;
import com.google.gwt.dev.js.ast.JsFunction;
import com.google.gwt.dev.js.ast.JsNameRef;
import com.google.gwt.dev.js.ast.JsParameter;
import com.google.gwt.dev.js.ast.JsVisitor;
import com.google.gwt.dev.util.Pair;
import com.google.gwt.thirdparty.guava.common.base.Predicate;
import com.google.gwt.thirdparty.guava.common.collect.FluentIterable;
import com.google.gwt.thirdparty.guava.common.collect.Iterables;
import com.google.gwt.thirdparty.guava.common.collect.Maps;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Checks and throws errors for invalid JsInterop constructs.
 */
public class JsInteropRestrictionChecker extends AbstractRestrictionChecker {

  public static void exec(TreeLogger logger, JProgram jprogram,
      MinimalRebuildCache minimalRebuildCache) throws UnableToCompleteException {
    JsInteropRestrictionChecker jsInteropRestrictionChecker =
        new JsInteropRestrictionChecker(jprogram, minimalRebuildCache);
    boolean success = jsInteropRestrictionChecker.checkProgram(logger);
    if (!success) {
      throw new UnableToCompleteException();
    }
  }

  private final JProgram jprogram;
  private final MinimalRebuildCache minimalRebuildCache;
  private boolean wasUnusableByJsWarningReported = false;

  private JsInteropRestrictionChecker(JProgram jprogram,
      MinimalRebuildCache minimalRebuildCache) {
    this.jprogram = jprogram;
    this.minimalRebuildCache = minimalRebuildCache;
  }

  /**
   * Returns true if the constructor method is locally empty (allows calls to init and super
   * constructor).
   */
  private static boolean isConstructorEmpty(final JConstructor constructor) {
    return Iterables.all(constructor.getBody().getStatements(), new Predicate<JStatement>() {
      @Override
      public boolean apply(JStatement statement) {
        JClassType type = constructor.getEnclosingType();
        if (isImplicitSuperCall(statement, type.getSuperClass())) {
          return true;
        }
        if (isInitCall(statement, type)) {
          return true;
        }
        return false;
      }
    });
  }

  private static JMethodCall isMethodCall(JStatement statement) {
    if (!(statement instanceof JExpressionStatement)) {
      return null;
    }
    JExpression expression = ((JExpressionStatement) statement).getExpr();

    return expression instanceof JMethodCall ? (JMethodCall) expression : null;
  }

  private static boolean isInitCall(JStatement statement, JDeclaredType type) {
    JMethodCall methodCall = isMethodCall(statement);

    return methodCall != null
        && methodCall.getTarget() == type.getInitMethod();
  }

  private static boolean isImplicitSuperCall(JStatement statement, JDeclaredType superType) {
    JMethodCall methodCall = isMethodCall(statement);

    return methodCall != null
        && methodCall.isStaticDispatchOnly()
        && methodCall.getTarget().isConstructor()
        && methodCall.getTarget().getEnclosingType() == superType;
  }

  private static boolean isInitEmpty(JDeclaredType type) {
    return type.getInitMethod() == null
        || ((JMethodBody) type.getInitMethod().getBody()).getStatements().isEmpty();
  }

  private void checkJsConstructors(JDeclaredType type) {
    List<JConstructor> jsConstructors = getJsConstructors(type);

    if (type.isJsNative()) {
      return;
    }

    if (jsConstructors.isEmpty()) {
      return;
    }

    if (jsConstructors.size() > 1) {
      logError(type,
          "More than one JsConstructor exists for %s.", getDescription(type));
    }

    final JConstructor jsConstructor = jsConstructors.get(0);

    if (JjsUtils.getPrimaryConstructor(type) != jsConstructor) {
      logError(jsConstructor,
          "Constructor %s can be a JsConstructor only if all constructors in the class are "
          + "delegating to it.", getMemberDescription(jsConstructor));
    }
  }

  private List<JConstructor> getJsConstructors(JDeclaredType type) {
    return FluentIterable
          .from(type.getConstructors())
          .filter(new Predicate<JConstructor>() {
            @Override
            public boolean apply(JConstructor m) {
              return m.isJsConstructor();
            }
          }).toList();
  }

  private void checkJsConstructorSubtype(JDeclaredType type) {
    if (!isJsConstructorSubtype(type)) {
      return;
    }
    if (Iterables.isEmpty(type.getConstructors())) {
      // No constructors in the type; type is not instantiable.
      return;
    }

    if (type.isJsNative()) {
      return;
    }

    JClassType superClass = type.getSuperClass();
    JConstructor superPrimaryConsructor = JjsUtils.getPrimaryConstructor(superClass);
    if (!superClass.isJsNative() && superPrimaryConsructor == null) {
      // Superclass has JsConstructor but does not satisfy the JsConstructor restrictions, no need
      // to report more errors.
      return;
    }

    JConstructor primaryConstructor = JjsUtils.getPrimaryConstructor(type);
    if (primaryConstructor == null) {
      logError(type,
          "Class %s should have only one constructor delegating to the superclass since it is "
              + "subclass of a a type with JsConstructor.", getDescription(type));
      return;
    }

    JConstructor delegatedConstructor =
        JjsUtils.getDelegatedThisOrSuperConstructor(primaryConstructor);

    if (delegatedConstructor.isJsConstructor() ||
        delegatedConstructor == superPrimaryConsructor) {
      return;
    }

    logError(primaryConstructor,
        "Constructor %s can only delegate to super constructor %s since it is a subclass of a "
            + "type with JsConstructor.",
        getDescription(primaryConstructor),
        getDescription(superPrimaryConsructor));
  }

  private void checkMember(
      JMember member, Map<String, JsMember> localNames, Map<String, JsMember> ownGlobalNames) {
    if (member.getEnclosingType().isJsNative()) {
      checkMemberOfNativeJsType(member);
    }

    if (member.needsDynamicDispatch()) {
      checkIllegalOverrides(member);
    }

    if (member instanceof JMethod) {
      checkMethodParameters((JMethod) member);
    }

    if (member.isJsOverlay()) {
      checkJsOverlay(member);
      return;
    }

    if (member.canBeReferencedExternally()) {
      checkUnusableByJs(member);
    }

    if (member.getJsMemberType() == JsMemberType.NONE) {
      return;
    }

    if (!checkJsPropertyAccessor(member)) {
      return;
    }

    checkMemberQualifiedJsName(member);

    if (isCheckedLocalName(member)) {
      checkLocalName(localNames, member);
    }

    if (isCheckedGlobalName(member)) {
      checkGlobalName(ownGlobalNames, member);
    }
  }

  private void checkIllegalOverrides(JMember member) {
    if (member instanceof JField) {
      return;
    }

    JMethod method = (JMethod) member;

    if (method.isSynthetic()) {
      // Ignore synthetic methods. These synthetic methods might be accidental overrides or
      // default method implementations, and they forward to the same implementation so it is
      // safe to allow them.
      return;
    }
    for (JMethod overriddenMethod : method.getOverriddenMethods()) {
      if (overriddenMethod.isSynthetic()) {
        // Ignore synthetic methods for a better error message.
        continue;
      }
      if (overriddenMethod.isJsOverlay()) {
        logError(member, "Method '%s' cannot override a JsOverlay method '%s'.",
            JjsUtils.getReadableDescription(method),
            JjsUtils.getReadableDescription(overriddenMethod));
        return;
      }
    }
  }

  private void checkJsOverlay(JMember member) {
    if (member.getEnclosingType().isJsoType() || member.isSynthetic()) {
      return;
    }

    String memberDescription = JjsUtils.getReadableDescription(member);

    if (!member.getEnclosingType().isJsNative() && !member.getEnclosingType().isJsFunction()) {
      logError(member,
          "JsOverlay '%s' can only be declared in a native type or a JsFunction interface.",
          memberDescription);
    }

    if (member instanceof JConstructor) {
      logError(member, "JsOverlay method '%s' cannot be a constructor.", memberDescription);
      return;
    }

    if (member.getJsMemberType() != JsMemberType.NONE) {
      logError(member, "JsOverlay method '%s' cannot be nor override a JsProperty or a JsMethod.",
          memberDescription);
      return;
    }

    if (member instanceof JField) {
      JField field = (JField) member;
      if (field.needsDynamicDispatch()) {
        logError(member, "JsOverlay field '%s' can only be static.", memberDescription);
      }
      return;
    }

    JMethod method = (JMethod) member;

    assert method.getOverriddenMethods().isEmpty();

    if (method.getBody() == null
        || (!method.isFinal()
            && !method.getEnclosingType().isFinal()
            && !method.isPrivate()
            && !method.isStatic()
            && !method.isDefaultMethod())) {
      logError(member, "JsOverlay method '%s' cannot be non-final nor native.", memberDescription);
    }
  }

  private void checkSuperDispachToNativeJavaLangObjectMethodOverride() {
    new JVisitor() {
      JClassType superClass;
      @Override
      public boolean visit(JDeclaredType x, Context ctx) {
        superClass = JjsUtils.getNativeSuperClassOrNull(x);
        // Only examine code in non native subclasses of native JsTypes.
        return x instanceof JClassType && superClass != null;
      }

      @Override
      public boolean visit(JMethod x, Context ctx) {
        // Do not report errors from synthetic method bodies, those errors are reported
        // explicitly elsewhere.
        return !x.isSynthetic();
      }

      @Override
      public void endVisit(JMethodCall x, Context ctx) {
        JMethod target = x.getTarget();
        if (!x.isStaticDispatchOnly()) {
          // Not a super call, allow.
          return;
        }

        assert (!target.isStatic());
        // Forbid calling through super when the target is the native implementation because
        // it might not exist in the native supertype at runtime.
        // TODO(rluble): lift this restriction by dispatching through a trampoline. Not that this
        // trampoline is different that the one created for non static dispatches.
        if ((overridesObjectMethod(target) && target.getEnclosingType().isJsNative())
            || target.getEnclosingType() == jprogram.getTypeJavaLangObject()) {
          logError(x, "Cannot use super to call '%s.%s'. 'java.lang.Object' methods in native "
              + "JsTypes cannot be called using super.",
              JjsUtils.getReadableDescription(superClass),
              target.getName());
          return;
        }
      }
    }.accept(jprogram);
  }

  private void checkMemberOfNativeJsType(JMember member) {
    if (member instanceof JMethod && ((JMethod) member).isJsniMethod()) {
      logError(member, "JSNI method %s is not allowed in a native JsType.",
          getMemberDescription(member));
      return;
    }

    if (member.isSynthetic() || member.isJsOverlay()) {
      return;
    }

    if (overridesObjectMethod(member)) {
      if (member.getJsMemberType() != JsMemberType.METHOD
          || !member.getName().equals(member.getJsName())) {
        logError(member,
            "Method %s cannot override a method from 'java.lang.Object' and change its name.",
            getMemberDescription(member));
        return;
      }
    }

    JsMemberType jsMemberType = member.getJsMemberType();
    switch (jsMemberType) {
      case CONSTRUCTOR:
        if (!isConstructorEmpty((JConstructor) member)) {
          logError(member, "Native JsType constructor %s cannot have non-empty method body.",
              getMemberDescription(member));
        }
        break;
      case METHOD:
      case GETTER:
      case SETTER:
      case UNDEFINED_ACCESSOR:
        JMethod method = (JMethod) member;
        if (!method.isAbstract() && method.getBody() != null) {
          logError(member, "Native JsType method %s should be native or abstract.",
              getMemberDescription(member));
        }
        break;
      case PROPERTY:
        JField field = (JField) member;
        if (field.isFinal()) {
          logError(member, "Native JsType field %s cannot be final.",
              getMemberDescription(member));
        } else if (field.hasInitializer()) {
          logError(member, "Native JsType field %s cannot have initializer.",
              getMemberDescription(member));
        }
        break;
      case NONE:
        logError(member, "Native JsType member %s cannot have @JsIgnore.",
            getMemberDescription(member));
        break;
    }
  }

  private boolean overridesObjectMethod(JMember member) {
    if (!(member instanceof JMethod)) {
      return false;
    }

    JMethod method = (JMethod) member;
    for (JMethod overriddenMethod : method.getOverriddenMethods()) {
      if (overriddenMethod.getEnclosingType() == jprogram.getTypeJavaLangObject()) {
        return true;
      }
    }
    return false;
  }

  private void checkMethodParameters(JMethod method) {
    if (method.isSynthetic()) {
      return;
    }

    boolean hasOptionalParameters = false;
    for (JParameter parameter : method.getParams()) {
      if (parameter.isOptional()) {
        if (parameter.getType().isPrimitiveType()) {
          logError(method, "JsOptional parameter '%s' in method %s cannot be of primitive type.",
              parameter.getName(), getMemberDescription(method));
        }
        hasOptionalParameters = true;
        continue;
      }
      if (hasOptionalParameters && !parameter.isVarargs()) {
        logError(method, "JsOptional parameter '%s' in method %s cannot precede parameters "
            + "that are not optional.", parameter.getName(), getMemberDescription(method));
        break;
      }
    }

    if (hasOptionalParameters
        && method.getJsMemberType() != JsMemberType.CONSTRUCTOR
        && method.getJsMemberType() != JsMemberType.METHOD
        && !method.isOrOverridesJsFunctionMethod()) {
      logError(method, "Method %s has JsOptional parameters and is not a JsMethod, "
          + "a JsConstructor or a JsFunction method.", getMemberDescription(method));
    }

    if (method.isJsMethodVarargs()) {
      checkJsVarargs(method);
    }

    // Check that parameters that are declared JsOptional in overridden methods remain JsOptional.
    for (JMethod overriddenMethod : method.getOverriddenMethods()) {
      for (int i = 0; i < overriddenMethod.getParams().size(); i++) {
        if (overriddenMethod.getParams().get(i).isOptional()) {
          if (!method.getParams().get(i).isOptional()) {
            logError(method, "Method %s should declare parameter '%s' as JsOptional",
                getMemberDescription(method), method.getParams().get(i).getName());
            return;
          }
          break;
        }
      }
    }
  }

  private void checkJsVarargs(final JMethod method) {
    if (!method.isJsniMethod()) {
      return;
    }
    final JsFunction function = ((JsniMethodBody) method.getBody()).getFunc();
    final JsParameter varargParameter = Iterables.getLast(function.getParameters());
    new JsVisitor() {
      @Override
      public void endVisit(JsNameRef x, JsContext ctx) {
        if (x.getName() == varargParameter.getName()) {
          logError(x, "Cannot access vararg parameter '%s' from JSNI in JsMethod %s."
              + " Use 'arguments' instead.", x.getIdent(),
              getMemberDescription(method));
        }
      }
    }.accept(function);
  }

  private boolean checkJsPropertyAccessor(JMember member) {
    JsMemberType memberType = member.getJsMemberType();

    if (member.getJsName().equals(JsInteropUtil.INVALID_JSNAME)) {
      assert memberType.isPropertyAccessor();
      logError(
          member,
          "JsProperty %s should either follow Java Bean naming conventions or provide a name.",
          getMemberDescription(member));
      return false;
    }

    switch (memberType) {
      case UNDEFINED_ACCESSOR:
        logError(member, "JsProperty %s should have a correct setter or getter signature.",
            getMemberDescription(member));
        break;
      case GETTER:
        if (member.getType() != JPrimitiveType.BOOLEAN && member.getName().startsWith("is")) {
          logError(member, "JsProperty %s cannot have a non-boolean return.",
              getMemberDescription(member));
        }
        break;
      case SETTER:
        if (((JMethod) member).getParams().get(0).isVarargs()) {
          logError(member, "JsProperty %s cannot have a vararg parameter.",
              getMemberDescription(member));
        }
        break;
    }

    if (memberType.isPropertyAccessor() && member.isStatic() && !member.isJsNative()) {
        logError(member, "Static property accessor '%s' can only be native.",
            JjsUtils.getReadableDescription(member));
    }

    return true;
  }

  private void checkMemberQualifiedJsName(JMember member) {
    if (member instanceof JConstructor) {
      // Constructors always inherit their name and namespace from the enclosing type.
      // The corresponding checks are done for the type separately.
      return;
    }

    checkJsName(member);

    if (member.getJsNamespace().equals(member.getEnclosingType().getQualifiedJsName())) {
      // Namespace set by the enclosing type has already been checked.
      return;
    }

    if (member.needsDynamicDispatch()) {
      logError(member, "Instance member %s cannot declare a namespace.",
          getMemberDescription(member));
      return;
    }

    checkJsNamespace(member);
  }

  private <T extends HasJsName & HasSourceInfo & CanBeJsNative> void checkJsName(T item) {
    if (item.getJsName().isEmpty()) {
      logError(item, "%s cannot have an empty name.", getDescription(item));
    } else if ((item.isJsNative() && !JsUtils.isValidJsQualifiedName(item.getJsName()))
        || (!item.isJsNative() && !JsUtils.isValidJsIdentifier(item.getJsName()))) {
      // Allow qualified names in the name field for JsPackage.GLOBAL native items for future
      // compatibility
      logError(item, "%s has invalid name '%s'.", getDescription(item), item.getJsName());
    }
  }

  private <T extends HasJsName & HasSourceInfo & CanBeJsNative> void checkJsNamespace(T item) {
    if (JsInteropUtil.isGlobal(item.getJsNamespace())) {
      return;
    }
    if (JsInteropUtil.isWindow(item.getJsNamespace())) {
      if (item.isJsNative()) {
        return;
      }
      logError(item, "'%s' can only be used as a namespace of native types and members.",
          item.getJsNamespace());
    } else if (item.getJsNamespace().isEmpty()) {
      logError(item, "%s cannot have an empty namespace.", getDescription(item));
    } else if (!JsUtils.isValidJsQualifiedName(item.getJsNamespace())) {
      logError(item, "%s has invalid namespace '%s'.", getDescription(item), item.getJsNamespace());
    }
  }

  private void checkLocalName(Map<String, JsMember> localNames, JMember member) {
    Pair<JsMember, JsMember> oldAndNewJsMember = updateJsMembers(localNames, member);
    JsMember oldJsMember = oldAndNewJsMember.left;
    JsMember newJsMember = oldAndNewJsMember.right;

    checkNameConsistency(member);
    checkJsPropertyConsistency(member, newJsMember);

    if (oldJsMember == null || oldJsMember == newJsMember) {
      return;
    }

    if (oldJsMember.isJsNative() && newJsMember.isJsNative()) {
      return;
    }

    logError(member, "%s and %s cannot both use the same JavaScript name '%s'.",
        getMemberDescription(member), getMemberDescription(oldJsMember.member), member.getJsName());
  }

  private void checkGlobalName(Map<String, JsMember> ownGlobalNames, JMember member) {
    Pair<JsMember, JsMember> oldAndNewJsMember = updateJsMembers(ownGlobalNames, member);
    JsMember oldJsMember = oldAndNewJsMember.left;
    JsMember newJsMember = oldAndNewJsMember.right;

    if (oldJsMember == newJsMember) {
      // We allow setter-getter to share the name if they are both defined in the same class, so
      // skipping the global name check. However still need to do a consistency check.
      checkJsPropertyConsistency(member, newJsMember);
      return;
    }

    String currentGlobalNameDescription =
        minimalRebuildCache.addExportedGlobalName(member.getQualifiedJsName(),
            JjsUtils.getReadableDescription(member), member.getEnclosingType().getName());
    if (currentGlobalNameDescription == null) {
      return;
    }
    logError(member, "%s cannot be exported because the global name '%s' is already taken by '%s'.",
        getMemberDescription(member), member.getQualifiedJsName(), currentGlobalNameDescription);
  }

  private void checkJsPropertyConsistency(JMember member, JsMember newMember) {
    if (newMember.setter != null && newMember.getter != null) {
      List<JParameter> setterParams = ((JMethod) newMember.setter).getParams();
      if (isSameType(newMember.getter.getType(), setterParams.get(0).getType())) {
        logError(member, "JsProperty setter %s and getter %s cannot have inconsistent types.",
            getMemberDescription(newMember.setter), getMemberDescription(newMember.getter));
      }
    }
  }

  /**
   * Returns true if {@code thisType} is the same type as {@code thatType}.
   */
  private boolean isSameType(JType thisType, JType thatType) {
    // NOTE: The comparison here is made by signature instead of reference equality because under
    // incremental compilation this types might be reference only and hence not unique.
    return !thisType.getJavahSignatureName().equals(thatType.getJavahSignatureName());
  }

  private void checkNameConsistency(JMember member) {
    if (member instanceof JMethod) {
      String jsName = member.getJsName();
      for (JMethod jMethod : ((JMethod) member).getOverriddenMethods()) {
        String parentName = jMethod.getJsName();
        if (parentName != null && !parentName.equals(jsName)) {
          logError(
              member,
              "%s cannot be assigned a different JavaScript name than the method it overrides.",
              getMemberDescription(member));
          break;
        }
      }
    }
  }

  private void checkStaticJsPropertyCalls() {
    new JVisitor() {
      @Override
      public boolean visit(JMethod x, Context ctx) {
        // Skip unnecessary synthetic override, as they will not be generated.
        return !JjsUtils.isJsMemberUnnecessaryAccidentalOverride(x);
      }

      @Override
      public void endVisit(JMethodCall x, Context ctx) {
        JMethod target = x.getTarget();
        if (x.isStaticDispatchOnly() && target.getJsMemberType().isPropertyAccessor()) {
          logError(x, "Cannot call property accessor %s via super.",
              getMemberDescription(target));
        }
      }
    }.accept(jprogram);
  }

  private void checkInstanceOfNativeJsTypesOrJsFunctionImplementations() {
    new JVisitor() {
      @Override
      public boolean visit(JInstanceOf x, Context ctx) {
        JReferenceType type = x.getTestType();
        if (type.isJsNative() && type instanceof JInterfaceType) {
          logError(x, "Cannot do instanceof against native JsType interface '%s'.",
              JjsUtils.getReadableDescription(type));
        } else if (type.isJsFunctionImplementation()) {
          logError(x, "Cannot do instanceof against JsFunction implementation '%s'.",
              JjsUtils.getReadableDescription(type));
        }
        return true;
      }
    }.accept(jprogram);
  }

  private boolean checkJsType(JDeclaredType type) {
    // Java (at least up to Java 8) does not allow to annotate anonymous classes or lambdas; if
    // it ever becomes possible we should emit an error.
    assert type.getClassDisposition() != NestedClassDisposition.ANONYMOUS
        && type.getClassDisposition() != NestedClassDisposition.LAMBDA;

    if  (type.getClassDisposition() == NestedClassDisposition.LOCAL) {
      logError("Local class '%s' cannot be a JsType.", type);
      return false;
    }

    return true;
  }

  private boolean checkNativeJsType(JDeclaredType type) {
    if (type.isEnumOrSubclass() != null) {
      logError("Enum '%s' cannot be a native JsType.", type);
      return false;
    }

    if (type.getClassDisposition() == NestedClassDisposition.INNER) {
      logError("Non static inner class '%s' cannot be a native JsType.", type);
      return false;
    }

    JClassType superClass = type.getSuperClass();
    if (superClass != null && superClass != jprogram.getTypeJavaLangObject() &&
        !superClass.isJsNative()) {
      logError("Native JsType '%s' can only extend native JsType classes.", type);
    }

    for (JInterfaceType interfaceType : type.getImplements()) {
      if (!interfaceType.isJsNative()) {
        logError(type, "Native JsType '%s' can only %s native JsType interfaces.",
            getDescription(type),
            type instanceof JInterfaceType ? "extend" : "implement");
      }
    }

    if (!isInitEmpty(type)) {
      logError("Native JsType '%s' cannot have initializer.", type);
    }

    return true;
  }

  private void checkMemberOfJsFunction(JMember member) {
    if (member.getJsMemberType() != JsMemberType.NONE) {
      logError(member,
          "JsFunction interface member '%s' cannot be JsMethod nor JsProperty.",
          JjsUtils.getReadableDescription(member));
    }

    if (member.isJsOverlay() || member.isSynthetic()) {
      return;
    }

    if (member instanceof JMethod && ((JMethod) member).isOrOverridesJsFunctionMethod()) {
      return;
    }

    logError(member, "JsFunction interface '%s' cannot declare non-JsOverlay member '%s'.",
        JjsUtils.getReadableDescription(member.getEnclosingType()),
        JjsUtils.getReadableDescription(member));
  }

  private void checkJsFunction(JDeclaredType type) {
    if (type.getImplements().size() > 0) {
      logError("JsFunction '%s' cannot extend other interfaces.", type);
    }

    if (type.isJsType()) {
      logError("'%s' cannot be both a JsFunction and a JsType at the same time.", type);
      return;
    }

    // Functional interface restriction already enforced by JSORestrictionChecker. It is safe
    // to assume here that there is a single abstract method.
    for (JMember member : type.getMembers()) {
      checkMemberOfJsFunction(member);
    }
  }

  private void checkMemberOfJsFunctionImplementation(JMember member) {
    if (member.getJsMemberType() != JsMemberType.NONE) {
      logError(member,
          "JsFunction implementation member '%s' cannot be JsMethod nor JsProperty.",
          JjsUtils.getReadableDescription(member));
    }

    if (!(member instanceof JMethod)) {
      return;
    }

    JMethod method = (JMethod) member;
    if (method.isOrOverridesJsFunctionMethod()
        || method.isSynthetic()
        || method.getOverriddenMethods().isEmpty()) {
      return;
    }

    // Methods that are not effectively static dispatch are disallowed. In this case these
    // could only be overridable methods of java.lang.Object, i.e. toString, hashCode and equals.
    logError(method, "JsFunction implementation '%s' cannot implement method '%s'.",
        JjsUtils.getReadableDescription(member.getEnclosingType()),
        JjsUtils.getReadableDescription(method));
  }

  private void checkJsFunctionImplementation(JDeclaredType type) {
    if (!type.isFinal()) {
      logError("JsFunction implementation '%s' must be final.",
          type);
    }

    if (type.getImplements().size() != 1) {
      logError("JsFunction implementation '%s' cannot implement more than one interface.",
          type);
    }

    if (type.getSuperClass() != jprogram.getTypeJavaLangObject()) {
      logError("JsFunction implementation '%s' cannot extend a class.", type);
    }

    if (type.isJsType()) {
      logError("'%s' cannot be both a JsFunction implementation and a JsType at the same time.",
          type);
      return;
    }
    for (JMember member : type.getMembers()) {
      checkMemberOfJsFunctionImplementation(member);
    }
  }

  private void checkJsFunctionSubtype(JDeclaredType type) {
    for (JInterfaceType superInterface : type.getImplements()) {
      if (superInterface.isJsFunction()) {
        logError(type, "'%s' cannot extend JsFunction '%s'.",
            JjsUtils.getReadableDescription(type), JjsUtils.getReadableDescription(superInterface));
      }
    }
  }

  private boolean checkProgram(TreeLogger logger) {
    for (JDeclaredType type : jprogram.getModuleDeclaredTypes()) {
      checkType(type);
    }
    checkStaticJsPropertyCalls();
    checkInstanceOfNativeJsTypesOrJsFunctionImplementations();
    checkSuperDispachToNativeJavaLangObjectMethodOverride();
    if (wasUnusableByJsWarningReported) {
      logSuggestion(
          "Suppress \"[unusable-by-js]\" warnings by adding a "
              + "`@SuppressWarnings(\"unusable-by-js\")` annotation to the corresponding member.");
    }

    boolean hasErrors = reportErrorsAndWarnings(logger);
    return !hasErrors;
  }

  private boolean isJsConstructorSubtype(JDeclaredType type) {
    JClassType superClass = type.getSuperClass();
    if (superClass == null) {
      return false;
    }

    if (JjsUtils.getJsConstructor(superClass) != null) {
      return true;
    }
    return isJsConstructorSubtype(superClass);
  }

  private static boolean isSubclassOfNativeClass(JDeclaredType type) {
    return JjsUtils.getNativeSuperClassOrNull(type) != null;
  }

  private void checkJsNameOnType(JDeclaredType type) {
    if (!type.getJsName().equals("*") && !type.getJsName().equals("?")) {
      checkJsName(type);
      return;
    }

    if (!type.isJsNative()
        || !(type instanceof JInterfaceType)
        || !JsInteropUtil.isGlobal(type.getJsNamespace())) {
      logError(type,
          "'%s' can only be used as a name for native interfaces in the global namespace.",
          type.getJsName());
    }
  }

  private void checkType(JDeclaredType type) {
    minimalRebuildCache.removeExportedNames(type.getName());

    if (type.isJsType()) {
      if (!checkJsType(type)) {
        return;
      }
      checkJsNameOnType(type);
      checkJsNamespace(type);
    }

    if (type.isJsNative()) {
      if (!checkNativeJsType(type)) {
        return;
      }
    } else if (isSubclassOfNativeClass(type)) {
      checkSubclassOfNativeClass(type);
    }

    if (type.isJsFunction()) {
      checkJsFunction(type);
    } else if (type.isJsFunctionImplementation()) {
      checkJsFunctionImplementation(type);
    } else {
      checkJsFunctionSubtype(type);
      checkJsConstructors(type);
      checkJsConstructorSubtype(type);
    }

    Map<String, JsMember> ownGlobalNames = Maps.newHashMap();
    Map<String, JsMember> localNames = collectLocalNames(type.getSuperClass());
    for (JMember member : type.getMembers()) {
      checkMember(member, localNames, ownGlobalNames);
    }
  }

  private void checkSubclassOfNativeClass(JDeclaredType type) {
    assert (type instanceof JClassType);
    for (JMethod method : type.getMethods()) {
      if (!overridesObjectMethod(method) || !method.isSynthetic()) {
        continue;
      }
      // Only look at synthetic (accidental) overrides.
      for (JMethod overridenMethod : method.getOverriddenMethods()) {
        if (overridenMethod.getEnclosingType() instanceof JInterfaceType
            && overridenMethod.getJsMemberType() != JsMemberType.METHOD) {
          logError(
              type,
              "Native JsType subclass %s can not implement interface %s that declares method '%s' "
                  + "inherited from java.lang.Object.",
              getDescription(type),
              getDescription(overridenMethod.getEnclosingType()),
              overridenMethod.getName());
        }
      }
    }
  }

  private void checkUnusableByJs(JMember member) {
    logIfUnusableByJs(member, member instanceof JField ? "Type of" : "Return type of", member);

    if (member instanceof JMethod) {
      for (JParameter parameter : ((JMethod) member).getParams()) {
        String prefix = String.format("Type of parameter '%s' in", parameter.getName());
        logIfUnusableByJs(parameter, prefix, member);
      }
    }
  }

  private <T extends HasType & CanHaveSuppressedWarnings> void logIfUnusableByJs(
      T hasType, String prefix, JMember x) {
    if (hasType.getType().canBeReferencedExternally()) {
      return;
    }
    if (isUnusableByJsSuppressed(x.getEnclosingType()) || isUnusableByJsSuppressed(x)
        || isUnusableByJsSuppressed(hasType)) {
      return;
    }
    logWarning(x, "[unusable-by-js] %s %s is not usable by but exposed to JavaScript.", prefix,
        getMemberDescription(x));
    wasUnusableByJsWarningReported = true;
  }

  private static class JsMember {
    private JMember member;
    private JMember setter;
    private JMember getter;

    public JsMember(JMember member) {
      this.member = member;
    }

    public JsMember(JMember member, JMember setter, JMember getter) {
      this.member = member;
      this.setter = setter;
      this.getter = getter;
    }

    public boolean isJsNative() {
      return member.isJsNative();
    }

    public boolean isPropertyAccessor() {
      return setter != null || getter != null;
    }
  }

  private LinkedHashMap<String, JsMember> collectLocalNames(JDeclaredType type) {
    if (type == null) {
      return Maps.newLinkedHashMap();
    }

    LinkedHashMap<String, JsMember> memberByLocalMemberNames =
        collectLocalNames(type.getSuperClass());
    for (JMember member : type.getMembers()) {
      if (isCheckedLocalName(member)) {
        updateJsMembers(memberByLocalMemberNames, member);
      }
    }
    return memberByLocalMemberNames;
  }

  private boolean isCheckedLocalName(JMember method) {
    return method.needsDynamicDispatch() && method.getJsMemberType() != JsMemberType.NONE
        && !isSyntheticBridgeMethod(method);
  }

  private boolean isSyntheticBridgeMethod(JMember member) {
    if (!(member instanceof JMethod)) {
      return false;
    }
    // A name slot taken up by a synthetic method, such as a bridge method for a generic method,
    // is not the fault of the user and so should not be reported as an error. JS generation
    // should take responsibility for ensuring that only the correct method version (in this
    // particular set of colliding method names) is exported. Forwarding synthetic methods
    // (such as an accidental override forwarding method that occurs when a JsType interface
    // starts exposing a method in class B that is only ever implemented in its parent class A)
    // though should be checked since they are exported and do take up an name slot.
    return member.isSynthetic() && !((JMethod) member).isForwarding();
  }

  private boolean isCheckedGlobalName(JMember member) {
    return !member.needsDynamicDispatch() && !member.isJsNative();
  }

  private Pair<JsMember, JsMember> updateJsMembers(
      Map<String, JsMember> memberByNames, JMember member) {
    JsMember oldJsMember = memberByNames.get(member.getJsName());
    JsMember newJsMember = createOrUpdateJsMember(oldJsMember, member);
    memberByNames.put(member.getJsName(), newJsMember);
    return Pair.create(oldJsMember, newJsMember);
  }

  private JsMember createOrUpdateJsMember(JsMember jsMember, JMember member) {
    switch (member.getJsMemberType()) {
      case GETTER:
        if (jsMember != null && jsMember.isPropertyAccessor()) {
          if (jsMember.getter == null || overrides(member, jsMember.getter)) {
            jsMember.getter = member;
            jsMember.member = member;
            return jsMember;
          }
        }
        return new JsMember(member, jsMember == null ? null : jsMember.setter, member);
      case SETTER:
        if (jsMember != null && jsMember.isPropertyAccessor()) {
          if (jsMember.setter == null || overrides(member, jsMember.setter)) {
            jsMember.setter = member;
            jsMember.member = member;
            return jsMember;
          }
        }
        return new JsMember(member, member, jsMember == null ? null : jsMember.getter);
      default:
        if (jsMember != null && !jsMember.isPropertyAccessor()) {
          if (overrides(member, jsMember.member)) {
            jsMember.member = member;
            return jsMember;
          }
        }
        return new JsMember(member);
    }
  }

  private boolean overrides(JMember member, JMember potentiallyOverriddenMember) {
    if (member instanceof JField || potentiallyOverriddenMember instanceof JField) {
      return false;
    }
    JMethod method = (JMethod) member;
    if (method.getOverriddenMethods().contains(potentiallyOverriddenMember)) {
      return true;
    }

    // Consider methods that have the same name and parameter signature to be overrides.
    // GWT models overrides similar to the JVM (not Java) in the sense that for a method to override
    // another they must have identical signatures (includes parameters and return type).
    // Methods that only differ in return types are Java overrides and need to be considered so
    // for local name collision checking.
    JMethod potentiallyOverriddenMethod = (JMethod) potentiallyOverriddenMember;

    // TODO(goktug): make this more precise to handle package visibilities.
    boolean visibilitiesMatchesForOverride =
        !method.isPackagePrivate() && !method.isPrivate()
        && !potentiallyOverriddenMethod.isPackagePrivate()
        && !potentiallyOverriddenMethod.isPrivate();

    return visibilitiesMatchesForOverride
        && method.getJsniSignature(false, false)
               .equals(potentiallyOverriddenMethod.getJsniSignature(false, false));
  }

  private boolean isUnusableByJsSuppressed(CanHaveSuppressedWarnings x) {
    return x.getSuppressedWarnings() != null &&
        x.getSuppressedWarnings().contains(JsInteropUtil.UNUSABLE_BY_JS);
  }
}
