use of com.google.javascript.jscomp.testing.TestExternsBuilder in project closure-compiler by google.
the class RemoveUnusedCodeTest method testRemoveUnusedPolyfills_prototypeProperty_untyped.
@Test
public void testRemoveUnusedPolyfills_prototypeProperty_untyped() {
final String stringRepeatPolyfill = "$jscomp.polyfill('String.prototype.repeat', function() {}, 'es6', 'es3');";
PolyfillRemovalTester tester = new PolyfillRemovalTester().addExterns(new TestExternsBuilder().addArray().addConsole().addString().addFunction().addAlert().addExtra(//
JSCOMP_POLYFILL, "function externFunction() {}", "").build()).addPolyfill(stringRepeatPolyfill);
// Unused polyfill is removed.
tester.expectPolyfillsRemovedTest("console.log();", stringRepeatPolyfill);
// Used polyfill is retained.
tester.expectNoRemovalTest("''.repeat(1);");
tester.expectNoRemovalTest("''?.repeat(1);");
// Guarded polyfill is removed.
tester.expectPolyfillsRemovedTest("''.repeat?.(1);", stringRepeatPolyfill);
// Used polyfill (directly via String.prototype) is retained.
tester.expectNoRemovalTest("String.prototype.repeat(1);");
tester.expectNoRemovalTest("String.prototype?.repeat(1);");
tester.expectPolyfillsRemovedTest("String.prototype.repeat?.(1);", stringRepeatPolyfill);
// Used polyfill (directly String.prototype and Function.prototype.call) is retained.
tester.expectNoRemovalTest("String.prototype.repeat.call('', 1);");
tester.expectNoRemovalTest("String.prototype.repeat.call?.('', 1);");
tester.expectPolyfillsRemovedTest("String.prototype.repeat?.call('', 1);", stringRepeatPolyfill);
// Unused polyfill is not removed if there is another property with the same name on an unknown
// type
tester.expectNoRemovalTest(lines(//
"var x = externFunction();", "x.repeat();"));
tester.expectPolyfillsRemovedTest(lines(//
"var x = externFunction();", "x.repeat?.();"), stringRepeatPolyfill);
// Without type information, cannot remove the polyfill.
tester.expectNoRemovalTest(lines(//
"class Repeatable {", " static repeat() {}", "};", "Repeatable.repeat();", ""));
// Without type information, cannot remove the polyfill.
tester.expectNoRemovalTest(lines(//
"class Repeatable {", " repeat() {}", "};", "var x = new Repeatable();", "x.repeat();", ""));
// Multiple same-name methods
final String stringIncludesPolyfill = "$jscomp.polyfill('String.prototype.includes', function() {}, 'es6', 'es3');";
final String arrayIncludesPolyfill = "$jscomp.polyfill('Array.prototype.includes', function() {}, 'es6', 'es3');";
tester.addPolyfill(//
stringIncludesPolyfill).addPolyfill(arrayIncludesPolyfill);
// The unused `String.prototype.repeat` polyfill is removed, but both of the
// `(Array|String).prototype.includes` polyfills are kept, since we aren't using type
// information to recognize which one is being called.
tester.expectPolyfillsRemovedTest("[].includes(5);", stringRepeatPolyfill);
}
use of com.google.javascript.jscomp.testing.TestExternsBuilder in project closure-compiler by google.
the class RemoveUnusedCodeTest method testRemoveUnusedPolyfills_chained.
@Test
public void testRemoveUnusedPolyfills_chained() {
final String weakMapPolyfill = "$jscomp.polyfill('WeakMap', function() { console.log(); }, 'es6', 'es3');";
// Polyfill of Map depends on WeakMap
final String mapPolyfill = "$jscomp.polyfill('Map', function() { new WeakMap(); }, 'es6', 'es3');";
// Polyfill of Set depends on Map
final String setPolyfill = "$jscomp.polyfill('Set', function() { new Map(); }, 'es6', 'es3');";
PolyfillRemovalTester tester = new PolyfillRemovalTester().addExterns(new TestExternsBuilder().addConsole().addExtra(JSCOMP_POLYFILL, "/** @constructor */ function Map() {}", "/** @constructor */ function Set() {}", "/** @constructor */ function WeakMap() {}").build()).addPolyfill(weakMapPolyfill).addPolyfill(mapPolyfill).addPolyfill(setPolyfill);
// Removes polyfills that are only referenced in other (removed) polyfills' definitions.
tester.inputSourceLines("function unused() { new Set(); }", "console.log();").expectSourceLines("console.log();").expectPolyfillsRemoved(weakMapPolyfill, mapPolyfill, setPolyfill).test();
// Chains can be partially removed if just an outer-most symbol is unreferenced.
tester.expectPolyfillsRemovedTest("console.log(new Map());", setPolyfill);
// Only requires a single reference to the outermost symbol to retain the whole chain.
tester.expectNoRemovalTest("console.log(new Set())");
}
use of com.google.javascript.jscomp.testing.TestExternsBuilder in project closure-compiler by google.
the class RewriteAsyncFunctionsTest method testInnerSuperReference.
@Test
public void testInnerSuperReference() {
test(externs(new TestExternsBuilder().addFunction().addJSCompLibraries().build()), srcs(lines("class A {", " m() {", " return this;", " }", "}", "class X extends A {", " async m() {", " const tmp = super.m;", " return tmp.call(null);", " }", "}")), expected(lines("class A {", " m() {", " return this;", " }", "}", "class X extends A {", " m() {", " const $jscomp$async$super$get$m = () => super.m;", " return $jscomp.asyncExecutePromiseGeneratorFunction(", " function* () {", " const tmp = $jscomp$async$super$get$m();", // type of tmp will indicate it requires `this` be provided, but will allow null.
" return tmp.call(null);", " });", " }", "}")));
// type of A.prototype.m
Color classAPropertyMType = findClassDefinition(getLastCompiler(), "A").findMethodDefinition("m").getRootNode().getColor();
Color classAInstanceType = getGlobalInstanceColor("A");
CodeSubTree classXMethodMDefinition = findClassDefinition(getLastCompiler(), "X").findMethodDefinition("m");
// Check type information on wrapper function for `super.m`
ImmutableList<Node> superMethodWrapperNameNodes = classXMethodMDefinition.findMatchingQNameReferences("$jscomp$async$super$get$m");
// one declaration and one reference
assertThat(superMethodWrapperNameNodes).hasSize(2);
// first name node is declaration
// const $jscomp$async$super$get$m = () => super.m;
Node wrapperDeclarationNameNode = superMethodWrapperNameNodes.get(0);
// arrow function has a Color representing a object
Node wrapperArrowFunction = wrapperDeclarationNameNode.getOnlyChild();
assertNode(wrapperArrowFunction).isArrowFunction().hasColorThat().isEqualTo(StandardColors.TOP_OBJECT);
// wrapper function variable has type matching the function itself
Color wrapperArrowColor = wrapperArrowFunction.getColor();
assertNode(wrapperDeclarationNameNode).hasColorThat().isEqualTo(wrapperArrowColor);
// get `super.m` from `() => `super.m`
Node superDotM = wrapperArrowFunction.getLastChild();
assertNode(superDotM).matchesQualifiedName("super.m").hasColorThat().isEqualTo(classAPropertyMType);
Node superNode = superDotM.getFirstChild();
assertNode(superNode).hasColorThat().isEqualTo(classAInstanceType);
// second name node is reference
// const tmp = $jscomp$async$super$get$m();
Node wrapperReferenceNameNode = superMethodWrapperNameNodes.get(1);
// optimization colors don't track function signatures
assertNode(wrapperReferenceNameNode).hasColorThat().isEqualTo(StandardColors.TOP_OBJECT);
// `$jscomp$async$super$get$m()`
Node wrapperCallNode = wrapperReferenceNameNode.getParent();
assertNode(wrapperCallNode).isCall().hasColorThat().isEqualTo(classAPropertyMType);
}
use of com.google.javascript.jscomp.testing.TestExternsBuilder in project closure-compiler by google.
the class RewriteAsyncFunctionsTest method testInnerArrowFunctionUsingArguments.
@Test
public void testInnerArrowFunctionUsingArguments() {
test(externs(new TestExternsBuilder().addArguments().addJSCompLibraries().build()), srcs(lines("class X {", " async m() {", " return new Promise((resolve, reject) => {", " return arguments;", " });", " }", "}")), expected(lines("class X {", " m() {", " const $jscomp$async$arguments = arguments;", " return $jscomp.asyncExecutePromiseGeneratorFunction(", " function* () {", " return new Promise((resolve, reject) => {", " return $jscomp$async$arguments", " });", " });", " }", "}")));
ImmutableList<Node> argumentsAliasRefs = findClassDefinition(getLastCompiler(), "X").findMethodDefinition("m").findMatchingQNameReferences("$jscomp$async$arguments");
// one declaration and 1 use
assertThat(argumentsAliasRefs).hasSize(2);
Color argumentsColor = getGlobalColor(StandardColors.ARGUMENTS_ID);
// declaration reference
// const $jscomp$async$arguments = arguments;
Node argumentsAliasDeclaration = argumentsAliasRefs.get(0);
Node argumentsValue = argumentsAliasDeclaration.getOnlyChild();
assertNode(argumentsValue).matchesQualifiedName("arguments").hasColorThat().isEqualTo(argumentsColor);
assertNode(argumentsAliasDeclaration).matchesQualifiedName("$jscomp$async$arguments").hasColorThat().isEqualTo(argumentsColor);
// usage reference
// return $jscomp$async$arguments;
Node argumentsAliasUsage = argumentsAliasRefs.get(1);
assertNode(argumentsAliasUsage).matchesQualifiedName("$jscomp$async$arguments").hasColorThat().isEqualTo(argumentsColor);
}
use of com.google.javascript.jscomp.testing.TestExternsBuilder in project closure-compiler by google.
the class CompilerTest method testExternsFileAsEntryPoint.
@Test
public void testExternsFileAsEntryPoint() throws Exception {
// Test that you can specify externs as entry points.
// This allows all inputs to be passed to the compiler under the --js flag,
// relying on dependency management to sort out which ones are externs or weak files
List<SourceFile> inputs = ImmutableList.of(SourceFile.fromCode("/externs.js", "/** @fileoverview @externs */ /** @const {number} */ var bar = 1;"), SourceFile.fromCode("/foo.js", "console.log(0);"));
List<ModuleIdentifier> entryPoints = ImmutableList.of(ModuleIdentifier.forFile("/externs.js"));
CompilerOptions options = createNewFlagBasedOptions();
options.setDependencyOptions(DependencyOptions.pruneForEntryPoints(entryPoints));
List<SourceFile> externs = ImmutableList.of(new TestExternsBuilder().addConsole().buildExternsFile("default_externs.js"));
Compiler compiler = new Compiler();
compiler.compile(externs, inputs, options);
Result result = compiler.getResult();
assertThat(result.errors).isEmpty();
// Empty since srcs are pruned.
assertThat(compiler.toSource()).isEmpty();
}
Aggregations