/* * Copyright 2015 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; import static com.google.javascript.jscomp.InlineAliases.ALIAS_CYCLE; /** Unit tests for {@link InlineAliases}. */ public class InlineAliasesTest extends Es6CompilerTestCase { @Override protected CompilerPass getProcessor(Compiler compiler) { return new InlineAliases(compiler); } @Override protected CompilerOptions getOptions() { CompilerOptions options = super.getOptions(); options.setJ2clPass(CompilerOptions.J2clPassMode.ON); return options; } public void testSimpleAliasInJSDoc() { test("function Foo(){}; var /** @const */ alias = Foo; /** @type {alias} */ var x;", "function Foo(){}; var /** @const */ alias = Foo; /** @type {Foo} */ var x;"); test( LINE_JOINER.join( "var ns={};", "function Foo(){};", "/** @const */ ns.alias = Foo;", "/** @type {ns.alias} */ var x;"), LINE_JOINER.join( "var ns={};", "function Foo(){};", "/** @const */ ns.alias = Foo;", "/** @type {Foo} */ var x;")); test( LINE_JOINER.join( "var ns={};", "function Foo(){};", "/** @const */ ns.alias = Foo;", "/** @type {ns.alias.Subfoo} */ var x;"), LINE_JOINER.join( "var ns={};", "function Foo(){};", "/** @const */ ns.alias = Foo;", "/** @type {Foo.Subfoo} */ var x;")); } public void testSimpleAliasInCode() { test("function Foo(){}; var /** @const */ alias = Foo; var x = new alias;", "function Foo(){}; var /** @const */ alias = Foo; var x = new Foo;"); test("var ns={}; function Foo(){}; /** @const */ ns.alias = Foo; var x = new ns.alias;", "var ns={}; function Foo(){}; /** @const */ ns.alias = Foo; var x = new Foo;"); test("var ns={}; function Foo(){}; /** @const */ ns.alias = Foo; var x = new ns.alias.Subfoo;", "var ns={}; function Foo(){}; /** @const */ ns.alias = Foo; var x = new Foo.Subfoo;"); } public void testAliasQualifiedName() { test( LINE_JOINER.join( "var ns = {};", "ns.Foo = function(){};", "/** @const */ ns.alias = ns.Foo;", "/** @type {ns.alias.Subfoo} */ var x;"), LINE_JOINER.join( "var ns = {};", "ns.Foo = function(){};", "/** @const */ ns.alias = ns.Foo;", "/** @type {ns.Foo.Subfoo} */ var x;")); test( LINE_JOINER.join( "var ns = {};", "ns.Foo = function(){};", "/** @const */ ns.alias = ns.Foo;", "var x = new ns.alias.Subfoo;"), LINE_JOINER.join( "var ns = {};", "ns.Foo = function(){};", "/** @const */ ns.alias = ns.Foo;", "var x = new ns.Foo.Subfoo;")); } public void testHoistedAliasesInCode() { // Unqualified test( LINE_JOINER.join( "function Foo(){};", "function Bar(){ var x = alias; };", "var /** @const */ alias = Foo;"), LINE_JOINER.join( "function Foo(){};", "function Bar(){ var x = Foo; };", "var /** @const */ alias = Foo;")); // Qualified test( LINE_JOINER.join( "var ns = {};", "ns.Foo = function(){};", "function Bar(){ var x = ns.alias; };", "/** @const */ ns.alias = ns.Foo;"), LINE_JOINER.join( "var ns = {};", "ns.Foo = function(){};", "function Bar(){ var x = ns.Foo; };", "/** @const */ ns.alias = ns.Foo;")); } public void testAliasCycleError() { testError( LINE_JOINER.join( "/** @const */ var x = y;", "/** @const */ var y = x;"), ALIAS_CYCLE); } public void testTransitiveAliases() { test( LINE_JOINER.join( "/** @const */ var ns = {};", "/** @constructor */ ns.Foo = function() {};", "/** @constructor */ ns.Foo.Bar = function() {};", "var /** @const */ alias = ns.Foo;", "var /** @const */ alias2 = alias.Bar;", "var x = new alias2"), LINE_JOINER.join( "/** @const */ var ns = {};", "/** @constructor */ ns.Foo = function() {};", "/** @constructor */ ns.Foo.Bar = function() {};", "var /** @const */ alias = ns.Foo;", "var /** @const */ alias2 = ns.Foo.Bar;", "var x = new ns.Foo.Bar;")); } public void testAliasChains() { // Unqualified test( LINE_JOINER.join( "/** @constructor */ var Foo = function() {};", "var /** @const */ alias1 = Foo;", "var /** @const */ alias2 = alias1;", "var x = new alias2"), LINE_JOINER.join( "/** @constructor */ var Foo = function() {};", "var /** @const */ alias1 = Foo;", "var /** @const */ alias2 = Foo;", "var x = new Foo;")); // Qualified test( LINE_JOINER.join( "/** @const */ var ns = {};", "/** @constructor */ ns.Foo = function() {};", "var /** @const */ alias1 = ns.Foo;", "var /** @const */ alias2 = alias1;", "var x = new alias2"), LINE_JOINER.join( "/** @const */ var ns = {};", "/** @constructor */ ns.Foo = function() {};", "var /** @const */ alias1 = ns.Foo;", "var /** @const */ alias2 = ns.Foo;", "var x = new ns.Foo;")); } public void testAliasedEnums() { test( "/** @enum {number} */ var E = { A : 1 }; var /** @const */ alias = E.A; alias;", "/** @enum {number} */ var E = { A : 1 }; var /** @const */ alias = E.A; E.A;"); } public void testIncorrectConstAnnotationDoesntCrash() { testSame("var x = 0; var /** @const */ alias = x; alias = 5; use(alias);"); testSame("var x = 0; var ns={}; /** @const */ ns.alias = x; ns.alias = 5; use(ns.alias);"); } public void testRedefinedAliasesNotRenamed() { testSame("var x = 0; var /** @const */ alias = x; x = 5; use(alias);"); } public void testDefinesAreNotInlined() { testSame("var ns = {}; var /** @define {boolean} */ alias = ns.Foo; var x = new alias;"); } public void testConstWithTypesAreNotInlined() { testSame( LINE_JOINER.join( "var /** @type {number} */ n = 5", "var /** @const {number} */ alias = n;", "var x = use(alias)")); } public void testPrivateVariablesAreNotInlined() { testSame("/** @private */ var x = 0; var /** @const */ alias = x; var y = alias;"); testSame("var x_ = 0; var /** @const */ alias = x_; var y = alias;"); } public void testShadowedAliasesNotRenamed() { testSame( LINE_JOINER.join( "var ns = {};", "ns.Foo = function(){};", "var /** @const */ alias = ns.Foo;", "function f(alias) {", " var x = alias", "}")); testSame( LINE_JOINER.join( "var ns = {};", "ns.Foo = function(){};", "var /** @const */ alias = ns.Foo;", "function f() {", " var /** @const */ alias = 5;", " var x = alias", "}")); testSame( LINE_JOINER.join( "/** @const */", "var x = y;", "function f() {", " var x = 123;", " function g() {", " return x;", " }", "}")); } }