// Copyright (c) 2012, 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 dart_backend;

class LocalPlaceholder {
  final String identifier;
  final Set<Node> nodes;
  LocalPlaceholder(this.identifier) : nodes = new Set<Node>();
  int get hashCode => identifier.hashCode;
  String toString() =>
      'local_placeholder[id($identifier), nodes($nodes)]';
}

class FunctionScope {
  final Set<String> parameterIdentifiers;
  final Set<LocalPlaceholder> localPlaceholders;
  FunctionScope()
      : parameterIdentifiers = new Set<String>(),
      localPlaceholders = new Set<LocalPlaceholder>();
  void registerParameter(Identifier node) {
    parameterIdentifiers.add(node.source.slowToString());
  }
}

class ConstructorPlaceholder {
  final Node node;
  final DartType type;
  final bool isRedirectingCall;
  ConstructorPlaceholder(this.node, this.type)
      : this.isRedirectingCall = false;
  // Note: factory redirection is not redirecting call!
  ConstructorPlaceholder.redirectingCall(this.node)
      : this.type = null, this.isRedirectingCall = true;
}

class DeclarationTypePlaceholder {
  final TypeAnnotation typeNode;
  final bool requiresVar;
  DeclarationTypePlaceholder(this.typeNode, this.requiresVar);
}

class SendVisitor extends ResolvedVisitor {
  final PlaceholderCollector collector;

  get compiler => collector.compiler;

  SendVisitor(this.collector, TreeElements elements) : super(elements);

  visitOperatorSend(Send node) {
  }

  visitForeignSend(Send node) {}

  visitSuperSend(Send node) {
    Element element = elements[node];
    if (element != null && element.isConstructor()) {
      collector.makeRedirectingConstructorPlaceholder(node.selector, element);
    } else {
      collector.tryMakeMemberPlaceholder(node.selector);
    }
  }

  visitDynamicSend(Send node) {
    final element = elements[node];
    if (element == null || !element.isErroneous()) {
      collector.tryMakeMemberPlaceholder(node.selector);
    }
  }

  visitClosureSend(Send node) {
    final element = elements[node];
    if (element != null) {
      collector.tryMakeLocalPlaceholder(element, node.selector);
    }
  }

  visitGetterSend(Send node) {
    final element = elements[node];
    // element == null means dynamic property access.
    if (element == null) {
      collector.tryMakeMemberPlaceholder(node.selector);
    } else if (element.isErroneous()) {
      return;
    } else if (element.isPrefix()) {
      // Node is prefix part in case of source 'lib.somesetter = 5;'
      collector.makeNullPlaceholder(node);
    } else if (Elements.isStaticOrTopLevel(element)) {
      // Unqualified or prefixed top level or static.
      collector.makeElementPlaceholder(node.selector, element);
    } else if (!element.isTopLevel()) {
      if (element.isInstanceMember()) {
        collector.tryMakeMemberPlaceholder(node.selector);
      } else {
        // May get FunctionExpression here in selector
        // in case of A(int this.f());
        if (node.selector is Identifier) {
          collector.tryMakeLocalPlaceholder(element, node.selector);
        } else {
          assert(node.selector is FunctionExpression);
        }
      }
    }
  }

  visitStaticSend(Send node) {
    final element = elements[node];
    if (Elements.isUnresolved(element)
        || identical(element, compiler.assertMethod)) {
      return;
    }
    if (element.isConstructor() || element.isFactoryConstructor()) {
      // Rename named constructor in redirection position:
      // class C { C.named(); C.redirecting() : this.named(); }
      if (node.receiver is Identifier
          && node.receiver.asIdentifier().isThis()) {
        assert(node.selector is Identifier);
        collector.makeRedirectingConstructorPlaceholder(node.selector, element);
      }
      return;
    }
    collector.makeElementPlaceholder(node.selector, element);
    // Another ugly case: <lib prefix>.<top level> is represented as
    // receiver: lib prefix, selector: top level.
    if (element.isTopLevel() && node.receiver != null) {
      assert(elements[node.receiver].isPrefix());
      // Hack: putting null into map overrides receiver of original node.
      collector.makeNullPlaceholder(node.receiver);
    }
  }

  internalError(String reason, {Node node}) {
    collector.internalError(reason, node: node);
  }

  visitTypeReferenceSend(Send node) {
    collector.makeElementPlaceholder(node.selector, elements[node]);
  }
}

class PlaceholderCollector extends Visitor {
  final Compiler compiler;
  final Set<String> fixedMemberNames; // member names which cannot be renamed.
  final Map<Element, ElementAst> elementAsts;
  final Set<Node> nullNodes;  // Nodes that should not be in output.
  final Set<Node> unresolvedNodes;
  final Map<Element, Set<Node>> elementNodes;
  final Map<FunctionElement, FunctionScope> functionScopes;
  final Map<LibraryElement, Set<Identifier>> privateNodes;
  final List<DeclarationTypePlaceholder> declarationTypePlaceholders;
  final Map<String, Set<Identifier>> memberPlaceholders;
  final Map<Element, List<ConstructorPlaceholder>> constructorPlaceholders;
  Map<String, LocalPlaceholder> currentLocalPlaceholders;
  Element currentElement;
  FunctionElement topmostEnclosingFunction;
  TreeElements treeElements;

  LibraryElement get coreLibrary => compiler.coreLibrary;
  FunctionElement get entryFunction => compiler.mainApp.find(Compiler.MAIN);

  get currentFunctionScope => functionScopes.putIfAbsent(
      topmostEnclosingFunction, () => new FunctionScope());

  PlaceholderCollector(this.compiler, this.fixedMemberNames, this.elementAsts) :
      nullNodes = new Set<Node>(),
      unresolvedNodes = new Set<Node>(),
      elementNodes = new Map<Element, Set<Node>>(),
      functionScopes = new Map<FunctionElement, FunctionScope>(),
      privateNodes = new Map<LibraryElement, Set<Identifier>>(),
      declarationTypePlaceholders = new List<DeclarationTypePlaceholder>(),
      memberPlaceholders = new Map<String, Set<Identifier>>(),
      constructorPlaceholders =
          new Map<Element, List<ConstructorPlaceholder>>();

  void collectFunctionDeclarationPlaceholders(
      FunctionElement element, FunctionExpression node) {
    if (element.isGenerativeConstructor() || element.isFactoryConstructor()) {
      DartType type = element.getEnclosingClass().thisType.asRaw();
      makeConstructorPlaceholder(node.name, element, type);
      Return bodyAsReturn = node.body.asReturn();
      if (bodyAsReturn != null && bodyAsReturn.isRedirectingFactoryBody) {
        // Factory redirection.
        FunctionElement redirectTarget = element.defaultImplementation;
        assert(redirectTarget != null && redirectTarget != element);
        type = redirectTarget.getEnclosingClass().thisType.asRaw();
        makeConstructorPlaceholder(
            bodyAsReturn.expression, redirectTarget, type);
      }
    } else if (Elements.isStaticOrTopLevel(element)) {
      // Note: this code should only rename private identifiers for class'
      // fields/getters/setters/methods.  Top-level identifiers are renamed
      // just to escape conflicts and that should be enough as we shouldn't
      // be able to resolve private identifiers for other libraries.
      makeElementPlaceholder(node.name, element);
    } else if (element.isMember()) {
      if (node.name is Identifier) {
        tryMakeMemberPlaceholder(node.name);
      } else {
        assert(node.name.asSend().isOperator);
      }
    }
  }

  void collectFieldDeclarationPlaceholders(Element element, Node node) {
    Identifier name = node is Identifier ? node : node.asSend().selector;
    if (Elements.isStaticOrTopLevel(element)) {
      makeElementPlaceholder(name, element);
    } else if (Elements.isInstanceField(element)) {
      tryMakeMemberPlaceholder(name);
    }
  }

  void collect(Element element) {
    this.currentElement = element;
    this.topmostEnclosingFunction = null;
    final ElementAst elementAst = elementAsts[element];
    this.treeElements = elementAst.treeElements;
    Node elementNode = elementAst.ast;
    if (element is FunctionElement) {
      collectFunctionDeclarationPlaceholders(element, elementNode);
    } else if (element is VariableListElement) {
      VariableDefinitions definitions = elementNode;
      for (Node definition in definitions.definitions) {
        final definitionElement = treeElements[definition];
        // definitionElement == null if variable is actually unused.
        if (definitionElement == null) continue;
        collectFieldDeclarationPlaceholders(definitionElement, definition);
      }
      makeVarDeclarationTypePlaceholder(definitions);
    } else {
      assert(element is ClassElement || element is TypedefElement);
    }
    currentLocalPlaceholders = new Map<String, LocalPlaceholder>();
    compiler.withCurrentElement(element, () {
      elementNode.accept(this);
    });
  }

  void tryMakeLocalPlaceholder(Element element, Identifier node) {
    bool isNamedOptionalParameter() {
      FunctionElement function = element.enclosingElement;
      FunctionSignature signature = function.functionSignature;
      if (!signature.optionalParametersAreNamed) return false;
      for (Element parameter in signature.optionalParameters) {
        if (identical(parameter, element)) return true;
      }
      return false;
    }

    // TODO(smok): Maybe we should rename privates as well, their privacy
    // should not matter if they are local vars.
    if (node.source.isPrivate()) return;
    if (element.isParameter() && isNamedOptionalParameter()) {
      currentFunctionScope.registerParameter(node);
    } else if (Elements.isLocal(element)) {
      makeLocalPlaceholder(node);
    }
  }

  void tryMakeMemberPlaceholder(Identifier node) {
    assert(node != null);
    if (node.source.isPrivate()) return;
    if (node is Operator) return;
    final identifier = node.source.slowToString();
    if (fixedMemberNames.contains(identifier)) return;
    memberPlaceholders.putIfAbsent(
        identifier, () => new Set<Identifier>()).add(node);
  }

  void makeTypePlaceholder(Node node, DartType type) {
    Send send = node.asSend();
    if (send != null) {
      // Prefix.
      assert(send.receiver is Identifier);
      assert(send.selector is Identifier);
      makeNullPlaceholder(send.receiver);
      node = send.selector;
    }
    makeElementPlaceholder(node, type.element);
  }

  void makeOmitDeclarationTypePlaceholder(TypeAnnotation type) {
    if (type == null) return;
    declarationTypePlaceholders.add(
        new DeclarationTypePlaceholder(type, false));
  }

  void makeVarDeclarationTypePlaceholder(VariableDefinitions node) {
    // TODO(smok): Maybe instead of calling this method and
    // makeDeclaratioTypePlaceholder have type declaration placeholder
    // collector logic in visitVariableDefinitions when resolver becomes better
    // and/or catch syntax changes.
    if (node.type == null) return;
    Element definitionElement = treeElements[node.definitions.nodes.head];
    bool requiresVar = !node.modifiers.isFinalOrConst();
    declarationTypePlaceholders.add(
        new DeclarationTypePlaceholder(node.type, requiresVar));
  }

  void makeNullPlaceholder(Node node) {
    assert(node is Identifier || node is Send);
    nullNodes.add(node);
  }

  void makeElementPlaceholder(Node node, Element element) {
    assert(element != null);
    if (identical(element, entryFunction)) return;
    if (identical(element.getLibrary(), coreLibrary)) return;
    if (element.getLibrary().isPlatformLibrary && !element.isTopLevel()) {
      return;
    }
    if (element == compiler.types.dynamicType.element) {
      internalError(
          'Should never make element placeholder for dynamic type element',
          node: node);
    }
    elementNodes.putIfAbsent(element, () => new Set<Node>()).add(node);
  }

  void makePrivateIdentifier(Identifier node) {
    assert(node != null);
    privateNodes.putIfAbsent(
        currentElement.getLibrary(), () => new Set<Identifier>()).add(node);
  }

  void makeUnresolvedPlaceholder(Node node) {
    unresolvedNodes.add(node);
  }

  void makeLocalPlaceholder(Identifier identifier) {
    LocalPlaceholder getLocalPlaceholder() {
      String name = identifier.source.slowToString();
      return currentLocalPlaceholders.putIfAbsent(name, () {
        LocalPlaceholder localPlaceholder = new LocalPlaceholder(name);
        currentFunctionScope.localPlaceholders.add(localPlaceholder);
        return localPlaceholder;
      });
    }

    getLocalPlaceholder().nodes.add(identifier);
  }

  void makeConstructorPlaceholder(Node node, Element element, DartType type) {
    assert(type != null);
    constructorPlaceholders
        .putIfAbsent(element, () => <ConstructorPlaceholder>[])
            .add(new ConstructorPlaceholder(node, type));
  }
  void makeRedirectingConstructorPlaceholder(Node node, Element element) {
    constructorPlaceholders
        .putIfAbsent(element, () => <ConstructorPlaceholder>[])
            .add(new ConstructorPlaceholder.redirectingCall(node));
  }

  void internalError(String reason, {Node node}) {
    compiler.cancel(reason, node: node);
  }

  void unreachable() { internalError('Unreachable case'); }

  visit(Node node) => (node == null) ? null : node.accept(this);

  visitNode(Node node) { node.visitChildren(this); }  // We must go deeper.

  visitNewExpression(NewExpression node) {
    Send send = node.send;
    InterfaceType type = treeElements.getType(node);
    assert(type != null);
    Element constructor = treeElements[send];
    assert(constructor != null);
    assert(send.receiver == null);
    if (!Elements.isErroneousElement(constructor)) {
      makeConstructorPlaceholder(node.send.selector, constructor, type);
      // TODO(smok): Should this be in visitNamedArgument?
      // Field names can be exposed as names of optional arguments, e.g.
      // class C {
      //   final field;
      //   C([this.field]);
      // }
      // Do not forget to rename them as well.
      FunctionElement constructorFunction = constructor;
      Link<Element> optionalParameters =
          constructorFunction.functionSignature.optionalParameters;
      for (final argument in send.argumentsNode) {
        NamedArgument named = argument.asNamedArgument();
        if (named == null) continue;
        Identifier name = named.name;
        String nameAsString = name.source.slowToString();
        for (final parameter in optionalParameters) {
          if (identical(parameter.kind, ElementKind.FIELD_PARAMETER)) {
            if (parameter.name.slowToString() == nameAsString) {
              tryMakeMemberPlaceholder(name);
              break;
            }
          }
        }
      }
    } else {
      makeUnresolvedPlaceholder(node.send.selector);
    }
    visit(node.send.argumentsNode);
  }

  visitSend(Send send) {
    new SendVisitor(this, treeElements).visitSend(send);
    send.visitChildren(this);
  }

  visitSendSet(SendSet send) {
    Element element = treeElements[send];
    if (Elements.isErroneousElement(element)) {
      // Complicated case: constructs like receiver.selector++ can resolve
      // to ErroneousElement.  Fortunately, receiver.selector still
      // can be resoved via treeElements[send.selector], that's all
      // that is needed to rename the construct properly.
      element = treeElements[send.selector];
    }
    if (element == null) {
      if (send.receiver != null) tryMakeMemberPlaceholder(send.selector);
    } else if (!element.isErroneous()) {
      if (Elements.isStaticOrTopLevel(element)) {
        // TODO(smok): Worth investigating why sometimes we get getter/setter
        // here and sometimes abstract field.
        assert(element.isClass() || element is VariableElement ||
               element.isAccessor() || element.isAbstractField() ||
               element.isFunction() || element.isTypedef() ||
               element is TypeVariableElement);
        makeElementPlaceholder(send.selector, element);
      } else {
        Identifier identifier = send.selector.asIdentifier();
        if (identifier == null) {
          // Handle optional function expression parameters with default values.
          identifier = send.selector.asFunctionExpression().name;
        }
        if (Elements.isInstanceField(element)) {
          tryMakeMemberPlaceholder(identifier);
        } else {
          tryMakeLocalPlaceholder(element, identifier);
        }
      }
    }
    send.visitChildren(this);
  }

  visitIdentifier(Identifier identifier) {
    if (identifier.source.isPrivate()) makePrivateIdentifier(identifier);
  }

  static bool isPlainTypeName(TypeAnnotation typeAnnotation) {
    if (typeAnnotation.typeName is !Identifier) return false;
    if (typeAnnotation.typeArguments == null) return true;
    if (typeAnnotation.typeArguments.isEmpty) return true;
    return false;
  }

  static bool isDynamicType(TypeAnnotation typeAnnotation) {
    if (!isPlainTypeName(typeAnnotation)) return false;
    String name = typeAnnotation.typeName.asIdentifier().source.slowToString();
    return name == 'dynamic';
  }

  visitTypeAnnotation(TypeAnnotation node) {
    // Poor man generic variables resolution.
    // TODO(antonm): get rid of it once resolver can deal with it.
    TypeDeclarationElement typeDeclarationElement;
    if (currentElement is TypeDeclarationElement) {
      typeDeclarationElement = currentElement;
    } else {
      typeDeclarationElement = currentElement.getEnclosingClass();
    }
    if (typeDeclarationElement != null && isPlainTypeName(node)
        && tryResolveAndCollectTypeVariable(
               typeDeclarationElement, node.typeName)) {
      return;
    }
    // We call [resolveReturnType] to allow having 'void'.
    final type = compiler.resolveReturnType(currentElement, node);
    if (type is InterfaceType || type is TypedefType) {
      // TODO(antonm): is there a better way to detect unresolved types?
      // Corner case: dart:core type with a prefix.
      // Most probably there are some additional problems with
      // coreLibPrefix.topLevels.
      if (!identical(type.element, compiler.types.dynamicType.element)) {
        makeTypePlaceholder(node.typeName, type);
      } else {
        if (!isDynamicType(node)) makeUnresolvedPlaceholder(node.typeName);
      }
    }
    // Visit only type arguments, otherwise in case of lib.Class type
    // annotation typeName is Send and we go to visitGetterSend, as a result
    // "Class" is added to member placeholders.
    visit(node.typeArguments);
  }

  visitVariableDefinitions(VariableDefinitions node) {
    // Collect only local placeholders.
    for (Node definition in node.definitions.nodes) {
      Element definitionElement = treeElements[definition];
      // definitionElement may be null if we're inside variable definitions
      // of a function that is a parameter of another function.
      // TODO(smok): Fix this when resolver correctly deals with
      // such cases.
      if (definitionElement == null) continue;
      Send send = definition.asSend();
      if (send != null) {
        // May get FunctionExpression here in definition.selector
        // in case of A(int this.f());
        if (send.selector is Identifier) {
          if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) {
            tryMakeMemberPlaceholder(send.selector);
          } else {
            tryMakeLocalPlaceholder(definitionElement, send.selector);
          }
        } else {
          assert(send.selector is FunctionExpression);
          if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) {
            tryMakeMemberPlaceholder(
                send.selector.asFunctionExpression().name);
          }
        }
      } else if (definition is Identifier) {
        tryMakeLocalPlaceholder(definitionElement, definition);
      } else if (definition is FunctionExpression) {
        // Skip, it will be processed in visitFunctionExpression.
      } else {
        internalError('Unexpected definition structure $definition');
      }
    }
    node.visitChildren(this);
  }

  visitFunctionExpression(FunctionExpression node) {
    bool isKeyword(Identifier id) =>
        id != null && Keyword.keywords[id.source.slowToString()] != null;

    Element element = treeElements[node];
    // May get null here in case of A(int this.f());
    if (element != null) {
      // Rename only local functions.
      if (topmostEnclosingFunction == null) {
        topmostEnclosingFunction = element;
      }
      if (!identical(element, currentElement)) {
        if (node.name != null) {
          assert(node.name is Identifier);
          tryMakeLocalPlaceholder(element, node.name);
        }
      }
    }
    node.visitChildren(this);
    // Make sure we don't omit return type of methods which names are
    // identifiers, because the following works fine:
    // int interface() => 1;
    // But omitting 'int' makes VM unhappy.
    // TODO(smok): Remove it when http://dartbug.com/5278 is fixed.
    if (node.name == null || !isKeyword(node.name.asIdentifier())) {
      makeOmitDeclarationTypePlaceholder(node.returnType);
    }
    collectFunctionParameters(node.parameters);
  }

  void collectFunctionParameters(NodeList parameters) {
    if (parameters == null) return;
    for (Node parameter in parameters.nodes) {
      if (parameter is NodeList) {
        // Optional parameter list.
        collectFunctionParameters(parameter);
      } else {
        assert(parameter is VariableDefinitions);
        makeOmitDeclarationTypePlaceholder(
            parameter.asVariableDefinitions().type);
      }
    }
  }

  visitClassNode(ClassNode node) {
    ClassElement classElement = currentElement;
    makeElementPlaceholder(node.name, classElement);
    node.visitChildren(this);
  }

  visitNamedMixinApplication(NamedMixinApplication node) {
    ClassElement classElement = currentElement;
    makeElementPlaceholder(node.name, classElement);
    node.visitChildren(this);
  }

  bool tryResolveAndCollectTypeVariable(
      TypeDeclarationElement typeDeclaration, Identifier name) {
    // Another poor man type resolution.
    // Find this variable in enclosing type declaration parameters.
    for (DartType type in typeDeclaration.typeVariables) {
      if (type.name.slowToString() == name.source.slowToString()) {
        makeTypePlaceholder(name, type);
        return true;
      }
    }
    return false;
  }

  visitTypeVariable(TypeVariable node) {
    assert(currentElement is TypedefElement || currentElement is ClassElement);
    tryResolveAndCollectTypeVariable(currentElement, node.name);
    node.visitChildren(this);
  }

  visitTypedef(Typedef node) {
    assert(currentElement is TypedefElement);
    makeElementPlaceholder(node.name, currentElement);
    node.visitChildren(this);
    makeOmitDeclarationTypePlaceholder(node.returnType);
    collectFunctionParameters(node.formals);
  }

  visitBlock(Block node) {
    for (Node statement in node.statements.nodes) {
      if (statement is VariableDefinitions) {
        makeVarDeclarationTypePlaceholder(statement);
      }
    }
    node.visitChildren(this);
  }
}
