content: // Copyright (c) 2011, 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;
  
  class TreeValidatorTask extends CompilerTask {
    TreeValidatorTask(Compiler compiler) : super(compiler);
  
    void validate(Node tree) {
      assert(check(tree));
    }
  
    bool check(Node tree) {
      List<InvalidNodeError> errors = [];
      void report(node, message) {
        final error = new InvalidNodeError(node, message);
        errors.add(error);
        compiler.reportWarning(node, message);
      };
      final validator = new ValidatorVisitor(report);
      tree.accept(new TraversingVisitor(validator));
  
      return errors.isEmpty;
    }
  }
  
  class ValidatorVisitor extends Visitor {
    final Function reportInvalidNode;
  
    ValidatorVisitor(Function this.reportInvalidNode);
  
    expect(Node node, bool test, [message]) {
      if (!test) reportInvalidNode(node, message);
    }
  
    visitNode(Node node) {}
  
    visitSendSet(SendSet node) {
      final selector = node.selector;
      final name = node.assignmentOperator.source;
      final arguments = node.arguments;
  
      expect(node, arguments != null);
      expect(node,
             selector is Identifier || selector is FunctionExpression,
             'selector is not assignable');
      if (identical(name, '++') || identical(name, '--')) {
        expect(node, node.assignmentOperator is Operator);
        if (node.isIndex) {
          expect(node.arguments.tail.head, node.arguments.tail.isEmpty);
        } else {
          expect(node.arguments.head, node.arguments.isEmpty);
        }
      } else {
        expect(node, !node.arguments.isEmpty);
      }
    }
  
    visitReturn(Return node) {
      if (!node.isRedirectingFactoryBody && node.hasExpression) {
        // We allow non-expression expressions in Return nodes, but only when
        // using them to hold redirecting factory constructors.
        expect(node, node.expression.asExpression() != null);
      }
    }
  }
  
  class InvalidNodeError {
    final Node node;
    final String message;
    InvalidNodeError(this.node, [this.message]);
  
    toString() {
      String nodeString = node.toDebugString();
      String result = 'invalid node: $nodeString';
      if (message != null) result = '$result ($message)';
      return result;
    }
  }
  