Package com.google.javascript.jscomp.parsing

Source Code of com.google.javascript.jscomp.parsing.IRFactoryTest

/*
* Copyright 2009 The Closure Compiler Authors.
*
* 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.javascript.jscomp.parsing;

import com.google.common.collect.Sets;
import com.google.javascript.jscomp.mozilla.rhino.CompilerEnvirons;
import com.google.javascript.jscomp.mozilla.rhino.Parser;
import com.google.javascript.jscomp.mozilla.rhino.ast.AstRoot;
import com.google.javascript.jscomp.parsing.Config.LanguageMode;
import com.google.javascript.jscomp.testing.TestErrorReporter;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.testing.BaseJSTypeTestCase;

/**
* Tests {@link IRFactory}.
*/
public class IRFactoryTest extends BaseJSTypeTestCase {

  private LanguageMode mode = LanguageMode.ECMASCRIPT3;

  @Override
  protected void setUp() throws Exception {
    super.setUp();
    mode = LanguageMode.ECMASCRIPT3;
  }

  public void testScript() throws Exception {
    parse("");
  }

  public void testStrictScript() throws Exception {
    assertNull(newParse("").getDirectives());
    assertEquals(
        Sets.newHashSet("use strict"),
        newParse("'use strict'").getDirectives());
  }

  public void testName() throws Exception {
    parse("a");
  }

  public void testArrayLiteral() throws Exception {
    parse("[a, b]");
  }

  public void testArrayLiteral2() throws Exception {
    testNewParser("[a, , b]",
      "SCRIPT 0 [length: 8]\n" +
      "    EXPR_RESULT 0 [length: 8]\n" +
      "        ARRAYLIT 0 [length: 8]\n" +
      "            NAME a 0 [length: 1]\n" +
      "            EMPTY 0 [length: 1]\n" +
      "            NAME b 0 [length: 1]\n");
  }

  public void testArrayLiteral3() throws Exception {
    parse("[a, undefined, b]");
  }

  public void testArrayLiteral4() throws Exception {
    testNewParser("[,,,a,,b]",
      "SCRIPT 0 [length: 9]\n" +
      "    EXPR_RESULT 0 [length: 9]\n" +
      "        ARRAYLIT 0 [length: 9]\n" +
      "            EMPTY 0 [length: 1]\n" +
      "            EMPTY 0 [length: 1]\n" +
      "            EMPTY 0 [length: 1]\n" +
      "            NAME a 0 [length: 1]\n" +
      "            EMPTY 0 [length: 1]\n" +
      "            NAME b 0 [length: 1]\n");
  }

  public void testAssignment() throws Exception {
    parse("a = b");
  }

  public void testAssignment2() throws Exception {
    parse("a += b");
  }

  public void testInfix() throws Exception {
    parse("a + b");
  }

  public void testScope() throws Exception {
    parse("{ a; b; c; }");
  }

  public void testConditional() throws Exception {
    parse("a ? b : c");
  }

  public void testEmpty() throws Exception {
    parse(";;");
  }

  public void testIf() throws Exception {
    parse("if (a) { b }");
  }

  public void testIf2() throws Exception {
    parse("if (a) { b } else { c }");
  }

  public void testNumber() throws Exception {
    parse("0");
  }

  public void testNumber2() throws Exception {
    parse("1.2");
  }

  public void testString() throws Exception {
    parse("'a'");
  }

  public void testString2() throws Exception {
    parse("\"a\"");
  }

  public void testUnary() throws Exception {
    parse("-a");
  }

  public void testUnary2() throws Exception {
    parse("a++");
  }

  public void testUnary3() throws Exception {
    parse("++a");
  }

  public void testVar() throws Exception {
    parse("var a = 1");
  }

  public void testVar2() throws Exception {
    parse("var a = 1, b = 2");
  }

  public void testVar3() throws Exception {
    parse("var a, b = 1");
  }

  public void testElementGet() throws Exception {
    parse("a[i]");
  }

  public void testPropertyGet() throws Exception {
    parse("a.b");
  }

  public void testRegexp() throws Exception {
    parse("/ab+c/");
  }

  public void testRegexp2() throws Exception {
    parse("/ab+c/g");
  }

  public void testFunctionCall() throws Exception {
    parse("a()");
  }

  public void testFunctionCall2() throws Exception {
    parse("a(b)");
  }

  public void testFunctionCall3() throws Exception {
    parse("a(b, c)");
  }

  public void testNew() throws Exception {
    parse("new A()");
  }

  public void testNew2() throws Exception {
    parse("new A(b)");
  }

  public void testNew3() throws Exception {
    parse("new A(b, c)");
  }

  public void testFunction() {
    parse("function f() {}");
  }

  public void testFunction2() {
    parse("(function() {})");
  }

  public void testFunction3() {
    parse("function f(a) {}");
  }

  public void testFunction4() {
    parse("(function(a) {})");
  }

  public void testFunction5() {
    parse("function f(a, b) {}");
  }

  public void testFunction6() {
    parse("(function(a, b) {})");
  }

  public void testReturn() {
    parse("(function() {return 1;})");
  }

  public void testReturn2() {
    parse("function f() {return;}");
  }

  public void testReturn3() {
    parse("function f(){return x?1:2}");
  }

  public void testThrow() {
    parse("throw e");
  }

  public void testWith() {
    parse("with (a) { b }");
  }

  public void testObjectLiteral() {
    newParse("var o = {}");
  }

  public void testObjectLiteral2() {
    newParse("var o = {a: 1}");
  }

  public void testObjectLiteral3() {
    newParse("var o = {a: 1, b: 2}");
  }

  public void testObjectLiteral4() {
    newParse("var o = {1: 'a'}");
  }

  public void testObjectLiteral5() {
    newParse("var o = {'a': 'a'}");
  }

  public void testObjectLiteral6() {
    testNewParser("({1: true})",
      "SCRIPT 0 [length: 11]\n" +
      "    EXPR_RESULT 0 [length: 10]\n" +
      "        OBJECTLIT 0 [parenthesized: true] [length: 9]\n" +
      "            STRING 1 0 [quoted: 1] [length: 1]\n" +
      "                TRUE 0 [length: 4]\n");
  }

  public void testObjectLiteral7() {
    mode = LanguageMode.ECMASCRIPT5;

    testNewParser("({get 1() {}})",
        "SCRIPT 0 [length: 14]\n" +
        "    EXPR_RESULT 0 [length: 13]\n" +
        "        OBJECTLIT 0 [parenthesized: true] [length: 12]\n" +
        "            GET 1 0 [quoted: 1] [length: 1]\n" +
        "                FUNCTION  0 [length: 6]\n" +
        "                    NAME  0\n" +
        "                    LP 0\n" +
        "                    BLOCK 0 [length: 2]\n");
  }

  public void testObjectLiteral8() {
    mode = LanguageMode.ECMASCRIPT5;

    testNewParser("({set 1(a) {}})",
        "SCRIPT 0 [length: 15]\n" +
        "    EXPR_RESULT 0 [length: 14]\n" +
        "        OBJECTLIT 0 [parenthesized: true] [length: 13]\n" +
        "            SET 1 0 [quoted: 1] [length: 1]\n" +
        "                FUNCTION  0 [length: 7]\n" +
        "                    NAME  0\n" +
        "                    LP 0\n" +
        "                        NAME a 0 [length: 1]\n" +
        "                    BLOCK 0 [length: 2]\n");
  }


  public void testKeywordLiteral() {
    parse("true");
  }

  public void testWhile() {
    parse("while (!a) { a--; }");
  }

  public void testParen() {
    parse("(a)");
  }

  public void testParen2() {
    parse("(1+1)*2");
  }

  public void testFor() {
    parse("for (var i = 0; i < n; i++) { a(i); }");
  }

  public void testForIn() {
    parse("for (i in a) { b(i); }");
  }

  public void testBreak() {
    parse("while (true) { break; }");
  }

  public void testContinue() {
    parse("while (true) { continue; }");
  }

  public void testDoLoop() {
    parse("do { a() } while (b());");
  }

  // The old and new parser produce different results now with labels, and
  // named breaks and continues, so disable these tests.
  public void testLabel() {
    testNewParser("foo: bar",
        "SCRIPT 0 [length: 8]\n" +
        "    LABEL 0 [length: 4]\n" +
        "        LABEL_NAME foo 0 [length: 4]\n" +
        "        EXPR_RESULT 0 [length: 3]\n" +
        "            NAME bar 0 [length: 3]\n");
  }

  public void testLabel2() {
    testNewParser("l: while (f()) { if (g()) { continue l; } }",
        "SCRIPT 0 [length: 43]\n" +
        "    LABEL 0 [length: 2]\n" +
        "        LABEL_NAME l 0 [length: 2]\n" +
        "        WHILE 0 [length: 40]\n" +
        "            CALL 0 [length: 3]\n" +
        "                NAME f 0 [length: 1]\n" +
        "            BLOCK 0 [length: 28]\n" +
        "                IF 0 [length: 24]\n" +
        "                    CALL 0 [length: 3]\n" +
        "                        NAME g 0 [length: 1]\n" +
        "                    BLOCK 0 [length: 15]\n" +
        "                        CONTINUE 0 [length: 11]\n" +
        "                            LABEL_NAME l 0 [length: 1]\n");
  }

  public void testLabel3() {
    testNewParser("Foo:Bar:X:{ break Bar; }",
        "SCRIPT 0 [length: 24]\n" +
        "    LABEL 0 [length: 4]\n" +
        "        LABEL_NAME Foo 0 [length: 4]\n" +
        "        LABEL 0 [length: 4]\n" +
        "            LABEL_NAME Bar 0 [length: 4]\n" +
        "            LABEL 0 [length: 2]\n" +
        "                LABEL_NAME X 0 [length: 2]\n" +
        "                BLOCK 0 [length: 14]\n" +
        "                    BREAK 0 [length: 10]\n" +
        "                        LABEL_NAME Bar 0 [length: 3]\n");
  }

  public void testNegation1() {
    testNewParser("-a",
        "SCRIPT 0 [length: 2]\n" +
        "    EXPR_RESULT 0 [length: 2]\n" +
        "        NEG 0 [length: 2]\n" +
        "            NAME a 0 [length: 1]\n");
  }

  public void testNegation2() {
    testNewParser("-2",
        "SCRIPT 0 [length: 2]\n" +
        "    EXPR_RESULT 0 [length: 2]\n" +
        "        NUMBER -2.0 0 [length: 1]\n");
  }

  public void testNegation3() {
    testNewParser("1 - -2",
        "SCRIPT 0 [length: 6]\n" +
        "    EXPR_RESULT 0 [length: 6]\n" +
        "        SUB 0 [length: 6]\n" +
        "            NUMBER 1.0 0 [length: 1]\n" +
        "            NUMBER -2.0 0 [length: 1]\n");
  }

  public void testGetter() {
    mode = LanguageMode.ECMASCRIPT5;
    testNewParser("({get a() {}})",
        "SCRIPT 0 [length: 14]\n" +
        "    EXPR_RESULT 0 [length: 13]\n" +
        "        OBJECTLIT 0 [parenthesized: true] [length: 12]\n" +
        "            GET a 0 [length: 1]\n" +
        "                FUNCTION  0 [length: 6]\n" +
        "                    NAME  0\n" +
        "                    LP 0\n" +
        "                    BLOCK 0 [length: 2]\n");
  }

  public void testSetter() {
    mode = LanguageMode.ECMASCRIPT5;
    testNewParser("({set a(x) {}})",
        "SCRIPT 0 [length: 15]\n" +
        "    EXPR_RESULT 0 [length: 14]\n" +
        "        OBJECTLIT 0 [parenthesized: true] [length: 13]\n" +
        "            SET a 0 [length: 1]\n" +
        "                FUNCTION  0 [length: 7]\n" +
        "                    NAME  0\n" +
        "                    LP 0\n" +
        "                        NAME x 0 [length: 1]\n" +
        "                    BLOCK 0 [length: 2]\n");
  }

  public void testSwitch() {
    parse("switch (e) {" +
        "case 'a': a(); break;" +
        "case 'b': b();" +
        "case 'c': c(); }");
  }

  public void testSwitch2() {
    parse("switch (e) { case 'a': a(); break; default: b();}");
  }

  public void testSwitch3() {
    parse("function f(){switch(x){default:case 1:return 2}}");
  }

  public void testDebugger() {
    parse("debugger;");
  }

  public void testDelete1() {
    testNoParseError("delete a.b;");
  }

  public void testDelete2() {
    testNoParseError("delete a['b'];");
  }

  public void testDelete3() {
    // This is allowed in ES3 and ES5, but not in ES5/strict. There
    // is a strict mode check for this.
    testNoParseError("delete a;");
  }

  public void testDelete4() {
    testParseError("delete 'x';",
        "Invalid delete operand. Only properties can be deleted.");
  }

  public void testCommentPositions1() {
    Node root = newParse("/** @param {string} x */function a(x) {};" +
        "/** @param {string} x */function b(x) {}");
    Node a = root.getFirstChild();
    Node b = root.getLastChild();
    assertMarkerPosition(a, 0, 4);
    assertMarkerPosition(b, 0, 45);
  }

  public void testCommentPositions2() {
    Node root = newParse(
        "/* foo \n" +
        "   bar \n" +
        "*/\n" +
        "/** @param {string} x */\n" +
        "function a(x) {};\n" +
        "\n" +
        "/* bar \n" +
        "   foo \n" +
        "   foo */\n" +
        "\n" +
        "/**   @param {string} x */\n" +
        "function b(x) {};");
    assertMarkerPosition(root.getFirstChild(), 3, 4);
    assertMarkerPosition(root.getFirstChild().getNext().getNext(), 10, 6);
  }

   public void testLiteralLocation() {
    Node root = newParse(
        "\nvar d =\n" +
        "    \"foo\";\n" +
        "var e =\n" +
        "    1;\n" +
        "var f = \n" +
        "    1.2;\n" +
        "var g = \n" +
        "    2e5;\n" +
        "var h = \n" +
        "    'bar';\n");

    Node firstStmt = root.getFirstChild();
    Node firstLiteral = firstStmt.getFirstChild().getFirstChild();
    Node secondStmt = firstStmt.getNext();
    Node secondLiteral = secondStmt.getFirstChild().getFirstChild();
    Node thirdStmt = secondStmt.getNext();
    Node thirdLiteral = thirdStmt.getFirstChild().getFirstChild();
    Node fourthStmt = thirdStmt.getNext();
    Node fourthLiteral = fourthStmt.getFirstChild().getFirstChild();
    Node fifthStmt = fourthStmt.getNext();
    Node fifthLiteral = fifthStmt.getFirstChild().getFirstChild();

    assertNodePosition(2, 4, firstLiteral);
    assertNodePosition(4, 4, secondLiteral);
    assertNodePosition(6, 4, thirdLiteral);
    assertNodePosition(8, 4, fourthLiteral);
    assertNodePosition(10, 4, fifthLiteral);
  }

  public void testSwitchLocation() {
    Node root = newParse(
        "\nswitch (a) {\n" +
        "  //{\n" +
        "   case 1:\n" +
        "     b++;\n" +
        "   case 2:\n" +
        "   default:\n" +
        "     b--;\n" +
        "  }\n");

    Node switchStmt = root.getFirstChild();
    Node switchVar = switchStmt.getFirstChild();
    Node firstCase = switchVar.getNext();
    Node caseArg = firstCase.getFirstChild();
    Node caseBody = caseArg.getNext();
    Node caseExprStmt = caseBody.getFirstChild();
    Node incrExpr = caseExprStmt.getFirstChild();
    Node incrVar = incrExpr.getFirstChild();
    Node secondCase = firstCase.getNext();
    Node defaultCase = secondCase.getNext();

    assertNodePosition(1, 0, switchStmt);
    assertNodePosition(1, 8, switchVar);
    assertNodePosition(3, 3, firstCase);
    assertNodePosition(3, 8, caseArg);
    assertNodePosition(3, 3, caseBody);
    assertNodePosition(4, 5, caseExprStmt);
    assertNodePosition(4, 5, incrExpr);
    assertNodePosition(4, 5, incrVar);
    assertNodePosition(5, 3, secondCase);
    assertNodePosition(6, 3, defaultCase);
  }

  public void testFunctionParamLocation() {
    Node root = newParse(
        "\nfunction\n" +
        "     foo(a,\n" +
        "     b,\n" +
        "     c)\n" +
        "{}\n");

    Node function = root.getFirstChild();
    Node functionName = function.getFirstChild();
    Node params = functionName.getNext();
    Node param1 = params.getFirstChild();
    Node param2 = param1.getNext();
    Node param3 = param2.getNext();
    Node body = params.getNext();

    assertNodePosition(1, 0, function);
    assertNodePosition(2, 5, functionName);
    // params corresponds to the LP token.
    // Can't be on a separate line because of inferred
    // semicolons.
    assertNodePosition(2, 8, params);
    assertNodePosition(2, 9, param1);
    assertNodePosition(3, 5, param2);
    assertNodePosition(4, 5, param3);
    assertNodePosition(5, 0, body);
  }

  public void testVarDeclLocation() {
    Node root = newParse(
        "\nvar\n" +
        "    a =\n" +
        "    3\n");
    Node varDecl = root.getFirstChild();
    Node varName = varDecl.getFirstChild();
    Node varExpr = varName.getFirstChild();

    assertNodePosition(1, 0, varDecl);
    assertNodePosition(2, 4, varName);
    assertNodePosition(3, 4, varExpr);
  }

  public void testReturnLocation() {
    Node root = newParse(
        "\nfunction\n" +
        "    foo(\n" +
        "    a,\n" +
        "    b,\n" +
        "    c) {\n" +
        "    return\n" +
        "    4;\n" +
        "}\n");

    Node function = root.getFirstChild();
    Node functionName = function.getFirstChild();
    Node params = functionName.getNext();
    Node body = params.getNext();
    Node returnStmt = body.getFirstChild();
    Node exprStmt = returnStmt.getNext();
    Node returnVal = exprStmt.getFirstChild();

    assertNodePosition(6, 4, returnStmt);
    assertNodePosition(7, 4, exprStmt);
    assertNodePosition(7, 4, returnVal);
  }

  public void testLinenoFor() {
    Node root = newParse(
        "\nfor(\n" +
        ";\n" +
        ";\n" +
        ") {\n" +
        "}\n");

    Node forNode = root.getFirstChild();
    Node initClause= forNode.getFirstChild();
    Node condClause = initClause.getNext();
    Node incrClause = condClause.getNext();

    assertNodePosition(1, 0, forNode);
    assertNodePosition(2, 0, initClause);
    assertNodePosition(3, 0, condClause);
    // TODO(bowdidge) Incorrectly gets charno position when EmptyExpression
    // has its absolute position on the carriage return.  For now, the
    // line number gets reported correctly (on the next line) but the
    // character position is -1, so the overall line/char pair in our tree
    // is -1.
    //assertNodePosition(4, 0, incrClause);
  }

  public void testBinaryExprLocation() {
    Node root = newParse(
        "\nvar d = a\n" +
        "    + \n" +
        "    b;\n" +
        "var\n" +
        "    e =\n" +
        "    a +\n" +
        "    c;\n" +
        "var f = b\n" +
        "    / c;\n");

    Node firstVarDecl = root.getFirstChild();
    Node firstVar = firstVarDecl.getFirstChild();
    Node firstVarAdd = firstVar.getFirstChild();

    Node secondVarDecl = firstVarDecl.getNext();
    Node secondVar = secondVarDecl.getFirstChild();
    Node secondVarAdd = secondVar.getFirstChild();

    Node thirdVarDecl = secondVarDecl.getNext();
    Node thirdVar = thirdVarDecl.getFirstChild();
    Node thirdVarAdd = thirdVar.getFirstChild();

    assertNodePosition(1, 0, firstVarDecl);
    assertNodePosition(1, 4, firstVar);
    assertNodePosition(2, 4, firstVarAdd);
    assertNodePosition(1, 8, firstVarAdd.getFirstChild());
    assertNodePosition(3, 4, firstVarAdd.getLastChild());

    assertNodePosition(4, 0, secondVarDecl);
    assertNodePosition(5, 4, secondVar);
    assertNodePosition(6, 6, secondVarAdd);
    assertNodePosition(6, 4, secondVarAdd.getFirstChild());
    assertNodePosition(7, 4, secondVarAdd.getLastChild());

    assertNodePosition(8, 0, thirdVarDecl);
    assertNodePosition(8, 4, thirdVar);
    assertNodePosition(9, 4, thirdVarAdd);
    assertNodePosition(8, 8, thirdVarAdd.getFirstChild());
    assertNodePosition(9, 6, thirdVarAdd.getLastChild());
  }

  public void testPrefixLocation() {
    Node root = newParse(
         "\na++;\n" +
         "--\n" +
         "b;\n");

    Node firstStmt = root.getFirstChild();
    Node secondStmt = firstStmt.getNext();
    Node firstOp = firstStmt.getFirstChild();
    Node secondOp = secondStmt.getFirstChild();

    assertNodePosition(1, 0, firstOp);
    assertNodePosition(2, 0, secondOp);
  }

  public void testIfLocation() {
    Node root = newParse(
        "\nif\n" +
        "  (a == 3)\n" +
        "{\n" +
        "  b = 0;\n" +
        "}\n" +
        "  else\n" +
        "{\n" +
        "  c = 1;\n" +
        "}\n");

    Node ifStmt = root.getFirstChild();
    Node eqClause = ifStmt.getFirstChild();
    Node thenClause = eqClause.getNext();
    Node elseClause = thenClause.getNext();

    assertNodePosition(1, 0, ifStmt);
    assertNodePosition(2, 5, eqClause);
    assertNodePosition(3, 0, thenClause);
    assertNodePosition(7, 0, elseClause);
  }

  public void testTryLocation() {
     Node root = newParse(
         "\ntry {\n" +
         "  var x = 1;\n" +
         "} catch\n" +
         "   (err)\n" +
         "{\n" +
         "} finally {\n" +
         "  var y = 2;\n" +
         "}\n");

    Node tryStmt = root.getFirstChild();
    Node tryBlock = tryStmt.getFirstChild();
    Node catchBlock = tryBlock.getNext();
    Node catchVarBlock = catchBlock.getFirstChild();
    Node catchVar = catchVarBlock.getFirstChild();
    Node finallyBlock = catchBlock.getNext();
    Node finallyStmt = finallyBlock.getFirstChild();

    assertNodePosition(1, 0, tryStmt);
    assertNodePosition(1, 4, tryBlock);
    assertNodePosition(3, 2, catchVarBlock);
    assertNodePosition(4, 4, catchVar);
    assertNodePosition(3, 0, catchBlock);
    assertNodePosition(6, 10, finallyBlock);
    assertNodePosition(7, 2, finallyStmt);
  }

  public void testHookLocation() {
    Node root = newParse(
        "\na\n" +
        "?\n" +
        "b\n" +
        ":\n" +
        "c\n" +
        ";\n");

    Node hookExpr = root.getFirstChild().getFirstChild();
    Node condExpr = hookExpr.getFirstChild();
    Node thenExpr = condExpr.getNext();
    Node elseExpr = thenExpr.getNext();

    assertNodePosition(2, 0, hookExpr);
    assertNodePosition(1, 0, condExpr);
    assertNodePosition(3, 0, thenExpr);
    assertNodePosition(5, 0, elseExpr);
  }

  public void testLabelLocation() {
    Node root = newParse(
        "\nfoo:\n" +
        "a = 1;\n" +
        "bar:\n" +
        "b = 2;\n");

    Node firstStmt = root.getFirstChild();
    Node secondStmt = firstStmt.getNext();

    assertNodePosition(1, 0, firstStmt);
    assertNodePosition(3, 0, secondStmt);
  }

  public void testCompareLocation() {
    Node root = newParse(
        "\na\n" +
        "<\n" +
        "b\n");

    Node condClause = root.getFirstChild().getFirstChild();
    Node lhs = condClause.getFirstChild();
    Node rhs = lhs.getNext();

    assertNodePosition(2, 0, condClause);
    assertNodePosition(1, 0, lhs);
    assertNodePosition(3, 0, rhs);
   }

  public void testEqualityLocation() {
    Node root = newParse(
        "\na\n" +
        "==\n" +
        "b\n");

    Node condClause = root.getFirstChild().getFirstChild();
    Node lhs = condClause.getFirstChild();
    Node rhs = lhs.getNext();

    assertNodePosition(2, 0, condClause);
    assertNodePosition(1, 0, lhs);
    assertNodePosition(3, 0, rhs);
  }

  public void testPlusEqLocation() {
    Node root = newParse(
        "\na\n" +
        "+=\n" +
        "b\n");

    Node condClause = root.getFirstChild().getFirstChild();
    Node lhs = condClause.getFirstChild();
    Node rhs = lhs.getNext();

    assertNodePosition(2, 0, condClause);
    assertNodePosition(1, 0, lhs);
    assertNodePosition(3, 0, rhs);
  }

  public void testCommaLocation() {
    Node root = newParse(
        "\na,\n" +
        "b,\n" +
        "c;\n");

    Node statement = root.getFirstChild();
    Node comma1 = statement.getFirstChild();
    Node comma2 = comma1.getFirstChild();
    Node cRef = comma2.getNext();
    Node aRef = comma2.getFirstChild();
    Node bRef = aRef.getNext();

    assertNodePosition(1, 1, comma2);
    assertNodePosition(1, 0, aRef);
    assertNodePosition(2, 0, bRef);
    assertNodePosition(3, 0, cRef);
  }

  public void testRegexpLocation() {
    Node root = newParse(
        "\nvar path =\n" +
        "replace(\n" +
        "/a/g," +
        "'/');\n");

    Node firstVarDecl = root.getFirstChild();
    Node firstVar = firstVarDecl.getFirstChild();
    Node firstInitializer = firstVar.getFirstChild();
    Node callNode = firstVar.getFirstChild();
    Node fnName = callNode.getFirstChild();
    Node regexObject = fnName.getNext();
    Node aString = regexObject.getFirstChild();
    Node endRegexString = regexObject.getNext();

    assertNodePosition(1, 0, firstVarDecl);
    assertNodePosition(1, 4, firstVar);
    assertNodePosition(2, 7, callNode);
    assertNodePosition(2, 0, fnName);
    assertNodePosition(3, 0, regexObject);
    assertNodePosition(3, 0, aString);
    assertNodePosition(3, 5, endRegexString);
  }

  public void testNestedOr() {
    Node root = newParse(
        "\nif (a && \n" +
        "    b() || \n" +
        "    /* comment */\n" +
        "    c) {\n" +
        "}\n"
    );

    Node ifStmt = root.getFirstChild();
    Node orClause = ifStmt.getFirstChild();
    Node andClause = orClause.getFirstChild();
    Node cName = andClause.getNext();

    assertNodePosition(1, 0, ifStmt);
    assertNodePosition(2, 8, orClause);
    assertNodePosition(1, 6, andClause);
    assertNodePosition(4, 4, cName);

  }

  public void testBitwiseOps() {
      Node root = newParse(
        "\nif (a & \n" +
        "    b() | \n" +
        "    /* comment */\n" +
        "    c) {\n" +
        "}\n"
    );

    Node ifStmt = root.getFirstChild();
    Node bitOr = ifStmt.getFirstChild();
    Node bitAnd = bitOr.getFirstChild();
    Node cName = bitAnd.getNext();

    assertNodePosition(1, 0, ifStmt);
    assertNodePosition(2, 8, bitOr);
    assertNodePosition(1, 6, bitAnd);
    assertNodePosition(4, 4, cName);

  }

  public void testObjectLitLocation() {
    Node root = newParse(
        "\nvar foo =\n" +
        "{ \n" +
        "'A' : 'A', \n" +
        "'B' : 'B', \n" +
        "'C' :\n" +
        "    'C' \n" +
        "};\n");

    Node firstVarDecl = root.getFirstChild();
    Node firstVar = firstVarDecl.getFirstChild();
    Node firstObjectLit = firstVar.getFirstChild();
    Node firstKey = firstObjectLit.getFirstChild();
    Node firstValue = firstKey.getFirstChild();

    Node secondKey = firstKey.getNext();
    Node secondValue = secondKey.getFirstChild();

    Node thirdKey = secondKey.getNext();
    Node thirdValue = thirdKey.getFirstChild();

    assertNodePosition(1, 4, firstVar);
    assertNodePosition(2, 0, firstObjectLit);

    assertNodePosition(3, 0, firstKey);
    assertNodePosition(3, 6, firstValue);

    assertNodePosition(4, 0, secondKey);
    assertNodePosition(4, 6, secondValue);

    assertNodePosition(5, 0, thirdKey);
    assertNodePosition(6, 4, thirdValue);
  }

  public void testTryWithoutCatchLocation() {
     Node root = newParse(
         "\ntry {\n" +
         "  var x = 1;\n" +
         "} finally {\n" +
         "  var y = 2;\n" +
         "}\n");

    Node tryStmt = root.getFirstChild();
    Node tryBlock = tryStmt.getFirstChild();
    Node catchBlock = tryBlock.getNext();
    Node finallyBlock = catchBlock.getNext();
    Node finallyStmt = finallyBlock.getFirstChild();

    assertNodePosition(1, 0, tryStmt);
    assertNodePosition(1, 4, tryBlock);
    assertNodePosition(3, 0, catchBlock);
    assertNodePosition(3, 10, finallyBlock);
    assertNodePosition(4, 2, finallyStmt);
  }

  public void testTryWithoutFinallyLocation() {
     Node root = newParse(
         "\ntry {\n" +
         "  var x = 1;\n" +
         "} catch (ex) {\n" +
         "  var y = 2;\n" +
         "}\n");

    Node tryStmt = root.getFirstChild();
    Node tryBlock = tryStmt.getFirstChild();
    Node catchBlock = tryBlock.getNext();
    Node catchStmt = catchBlock.getFirstChild();
    Node exceptionVar = catchStmt.getFirstChild();
    Node exceptionBlock = exceptionVar.getNext();
    Node varDecl = exceptionBlock.getFirstChild();

    assertNodePosition(1, 0, tryStmt);
    assertNodePosition(1, 4, tryBlock);
    assertNodePosition(3, 0, catchBlock);
    assertNodePosition(3, 2, catchStmt);
    assertNodePosition(3, 9, exceptionVar);
    assertNodePosition(3, 13, exceptionBlock);
    assertNodePosition(4, 2, varDecl);
  }

  public void testMultilineEqLocation() {
    Node  root = newParse(
        "\nif\n" +
        "    (((a == \n" +
        "  3) && \n" +
        "  (b == 2)) || \n" +
        " (c == 1)) {\n" +
        "}\n");
    Node ifStmt = root.getFirstChild();
    Node orTest = ifStmt.getFirstChild();
    Node andTest = orTest.getFirstChild();
    Node cTest = andTest.getNext();
    Node aTest = andTest.getFirstChild();
    Node bTest = aTest.getNext();

    assertNodePosition(1, 0, ifStmt);
    assertNodePosition(4, 12, orTest);
    assertNodePosition(3, 5, andTest);
    assertNodePosition(2, 9, aTest);
    assertNodePosition(4, 5, bTest);
    assertNodePosition(5, 4, cTest);
  }

  public void testMultilineBitTestLocation() {
    Node root = newParse(
        "\nif (\n" +
        "      ((a \n" +
        "        | 3 \n" +
        "       ) == \n" +
        "       (b \n" +
        "        & 2)) && \n" +
        "      ((a \n" +
        "         ^ 0xffff) \n" +
        "       != \n" +
        "       (c \n" +
        "        << 1))) {\n" +
        "}\n");

    Node ifStmt = root.getFirstChild();
    Node andTest = ifStmt.getFirstChild();
    Node eqTest = andTest.getFirstChild();
    Node notEqTest = eqTest.getNext();

    Node bitOrTest = eqTest.getFirstChild();
    Node bitAndTest = bitOrTest.getNext();

    Node bitXorTest = notEqTest.getFirstChild();
    Node bitShiftTest = bitXorTest.getNext();

    assertNodePosition(1, 0, ifStmt);

    assertNodePosition(4, 9, eqTest);
    assertNodePosition(9, 7, notEqTest);

    assertNodePosition(3, 8, bitOrTest);
    assertNodePosition(6, 8, bitAndTest);
    assertNodePosition(8, 9, bitXorTest);
    assertNodePosition(11, 8, bitShiftTest);
  }

  public void testCallLocation() {
    Node root = newParse(
        "\na.\n" +
        "b.\n" +
        "cccc(1);\n");

    Node exprStmt = root.getFirstChild();
    Node functionCall = exprStmt.getFirstChild();
    Node functionProp = functionCall.getFirstChild();
    Node firstNameComponent = functionProp.getFirstChild();
    Node lastNameComponent = firstNameComponent.getNext();

    assertNodePosition(3, 4, functionCall);
    // TODO(bowdidge) New Rhino doesn't keep the position of the dot handy.
    // New Rhino treats the location of the qualified name as the beginning of
    // the whole name.
    // assertNodePosition(1, 0, firstNameComponent);
    assertNodePosition(3, 0, lastNameComponent);
  }

  public void testLinenoDeclaration() {
    Node root = newParse(
        "\na.\n" +
        "b=\n" +
        "function() {};\n");

    Node exprStmt = root.getFirstChild();
    Node fnAssignment =  exprStmt.getFirstChild();
    Node aDotbName = fnAssignment.getFirstChild();
    Node aName = aDotbName.getFirstChild();
    Node bName = aName.getNext();
    Node fnNode = aDotbName.getNext();
    Node fnName = fnNode.getFirstChild();

    assertNodePosition(2, 1, fnAssignment);
    // TODO(bowdidge) New Rhino doesn't keep track of the position of the dot.
    //assertNodePosition(1, 1, aDotbName);
    assertNodePosition(1, 0, aName);
    assertNodePosition(2, 0, bName);
    assertNodePosition(3, 0, fnNode);
    assertNodePosition(3, 8, fnName);
  }

  final String INVALID_ASSIGNMENT_TARGET = "invalid assignment target";
  final String INVALID_INCREMENT_TARGET = "invalid increment target";
  final String INVALID_DECREMENT_TARGET = "invalid decrement target";

  final String INVALID_INC_OPERAND = "Invalid increment operand";
  final String INVALID_DEC_OPERAND = "Invalid decrement operand";

  public void testAssignmentValidation() {
    testNoParseError("x=1");
    testNoParseError("x.y=1");
    testNoParseError("f().y=1");
    testParseError("(x||y)=1", INVALID_ASSIGNMENT_TARGET);
    testParseError("(x?y:z)=1", INVALID_ASSIGNMENT_TARGET);
    testParseError("f()=1", INVALID_ASSIGNMENT_TARGET);

    testNoParseError("x+=1");
    testNoParseError("x.y+=1");
    testNoParseError("f().y+=1");
    testParseError("(x||y)+=1", INVALID_ASSIGNMENT_TARGET);
    testParseError("(x?y:z)+=1", INVALID_ASSIGNMENT_TARGET);
    testParseError("f()+=1", INVALID_ASSIGNMENT_TARGET);

    testParseError("f()++", INVALID_INCREMENT_TARGET);
    testParseError("f()--", INVALID_DECREMENT_TARGET);
    testParseError("++f()", INVALID_INCREMENT_TARGET);
    testParseError("--f()", INVALID_DECREMENT_TARGET);
  }

  private void testNoParseError(String string) {
    testParseError(string, (String)null);
  }

  private void testParseError(String string, String error) {
    testParseError(string, error == null ? null : new String[] { error });
  }

  private void testParseError(String string, String[] errors) {
    Node root = newParse(string, new TestErrorReporter(errors, null));
    assertTrue("unexpected warnings reported",
        errorReporter.hasEncounteredAllWarnings());
    assertTrue("expected error were not reported",
        errorReporter.hasEncounteredAllErrors());
  }

  private void assertMarkerPosition(Node n, int lineno, int charno) {
    int count = 0;
    for (JSDocInfo.Marker marker : n.getJSDocInfo().getMarkers()) {
      assertEquals(lineno, marker.getAnnotation().getStartLine());
      assertEquals(charno, marker.getAnnotation().getPositionOnStartLine());
      count++;
    }
    assertEquals(1, count);
  }

  private void assertNodePosition(int lineno, int charno, Node n) {
    assertEquals("Line number", lineno, n.getLineno());
    assertEquals("Column position", charno, n.getCharno());
  }

  private void testNewParser(String code, String expected) {
    String actual = newParse(code).toStringTree();
    assertEquals(expected, actual);
  }

  private void parse(String string) {
    String compare = newParse(string).checkTreeEquals(oldParse(string));
    assertTrue(compare, compare == null);
  }

  private Node newParse(String string) {
    return newParse(string, new TestErrorReporter(null, null));
  }

  private Node newParse(String string, TestErrorReporter errorReporter) {
    CompilerEnvirons environment = new CompilerEnvirons();

    environment.setRecordingComments(true);
    environment.setRecordingLocalJsDocComments(true);

    Parser p = new Parser(environment);
    AstRoot script = p.parse(string, null, 0);

    Config config = ParserRunner.createConfig(true, mode, false);
    Node root = IRFactory.transformTree(
        script, null, string, config, errorReporter);

    return root;
  }

  private Node oldParse(String string) {
    com.google.javascript.rhino.CompilerEnvirons environment =
        new com.google.javascript.rhino.CompilerEnvirons();

    environment.setParseJSDoc(true);

    com.google.javascript.rhino.Parser p =
        new com.google.javascript.rhino.Parser(environment, null);

    Node root = p.parse(string, null, 0);

    return root;
  }
}
TOP

Related Classes of com.google.javascript.jscomp.parsing.IRFactoryTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.