Skip to content

Commit

Permalink
RemoveUnusedCode: Treat function expression name as an alias
Browse files Browse the repository at this point in the history
Fixes #2822

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=187405970
  • Loading branch information
brad4d authored and Tyler Breisacher committed Mar 3, 2018
1 parent 5f8d256 commit 3cf8be8
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/com/google/javascript/jscomp/RemoveUnusedCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,12 @@ private void traverseFunction(Node function, Scope parentScope) {
if (!nameNode.getString().isEmpty()) {
// var x = function funcName() {};
// make sure funcName gets into the varInfoMap so it will be considered for removal.
traverseNameNode(nameNode, fparamScope);
VarInfo varInfo = traverseNameNode(nameNode, fparamScope);
if (NodeUtil.isExpressionResultUsed(function)) {
// var f = function g() {};
// The f is an alias for g, so g escapes from the scope where it is defined.
varInfo.hasNonLocalOrNonLiteralValue = true;
}
}

traverseChildren(paramlist, fparamScope);
Expand Down
33 changes: 33 additions & 0 deletions test/com/google/javascript/jscomp/IntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,39 @@ public final class IntegrationTest extends IntegrationTestCase {
private static final String CLOSURE_COMPILED =
"var COMPILED = true; var goog$exportSymbol = function() {};";

public void testIssue2822() {
CompilerOptions options = createCompilerOptions();
CompilationLevel.ADVANCED_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
test(
options,
lines(
// this method will get inlined into the constructor
"function classCallCheck(obj, ctor) {",
" if (!(obj instanceof ctor)) {",
" throw new Error('cannot call a class as a function');",
" }",
"}",
"/** @constructor */",
"var C = function InnerC() {",
// Before inlining happens RemoveUnusedCode sees one use of InnerC,
// which prevents its removal.
// After inlining it sees `this instanceof InnerC` as the only use of InnerC.
// Make sure RemoveUnusedCode recognizes that the value of InnerC escapes.
" classCallCheck(this, InnerC);",
"};",
// This creates an instance of InnerC, so RemoveUnusedCode should not replace
// `this instanceof InnerC` with `false`.
"alert(new C());"),
lines(
"alert(",
" new function a() {",
" if (!(this instanceof a)) {",
" throw Error(\"cannot call a class as a function\");",
" }",
" })",
""));
}

public void testNoInline() {
CompilerOptions options = createCompilerOptions();
CompilationLevel.ADVANCED_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public final class RemoveUnusedCodeNameAnalyzerTest extends TypeICompilerTestCas
"function Object(opt_value) {}",
"/** @type {Function} */",
"Object.defineProperties = function() {};",
"/**",
" * @constructor",
" * @param {string} message",
" */",
"function Error(message) {}",
"var window, top, console;",
"var document;",
"var Function;",
Expand Down Expand Up @@ -1333,6 +1338,18 @@ public void testDoNotChangeInstanceOfGetElem() {
+ "window['f'] = f;");
}

public void testIssue2822() {
testSame(
lines(
"var C = function C() {",
" if (!(this instanceof C)) {",
" throw new Error('not an instance');",
" }",
"}",
"use(new C());",
""));
}

public void testWeirdnessOnLeftSideOfPrototype() {
// This checks a bug where 'x' was removed, but the function referencing
// it was not, causing problems.
Expand Down

0 comments on commit 3cf8be8

Please sign in to comment.