aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkzc <zaxxon2011@gmail.com>2016-04-10 15:41:38 -0400
committerRichard van Velzen <rvanvelzen@experty.com>2016-04-11 18:15:20 +0200
commit3907a5e3b2c40904f2cb333ede23d6d59bb48c13 (patch)
treec36832ce2ab7e53025f14fd625a7561165403619
parentb434b75b3676f5e3f42bf3817ac7dc1ab898b3d2 (diff)
downloadtracifyjs-3907a5e3b2c40904f2cb333ede23d6d59bb48c13.tar.gz
tracifyjs-3907a5e3b2c40904f2cb333ede23d6d59bb48c13.zip
Fix warnings for referenced non-hoisted functions.
Fixes #1034 Also added `expect_warnings` functionality to test framework.
-rw-r--r--lib/compress.js4
-rw-r--r--test/compress/issue-1034.js137
-rwxr-xr-xtest/run-tests.js28
3 files changed, 167 insertions, 2 deletions
diff --git a/lib/compress.js b/lib/compress.js
index d42f84d1..e47be97b 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -801,7 +801,9 @@ merge(Compressor.prototype, {
};
function extract_declarations_from_unreachable_code(compressor, stat, target) {
- compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
+ if (!(stat instanceof AST_Defun)) {
+ compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
+ }
stat.walk(new TreeWalker(function(node){
if (node instanceof AST_Definitions) {
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
diff --git a/test/compress/issue-1034.js b/test/compress/issue-1034.js
new file mode 100644
index 00000000..039af2ed
--- /dev/null
+++ b/test/compress/issue-1034.js
@@ -0,0 +1,137 @@
+non_hoisted_function_after_return: {
+ options = {
+ hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
+ evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
+ if_return: true, join_vars: true, cascade: true, side_effects: true
+ }
+ input: {
+ function foo(x) {
+ if (x) {
+ return bar();
+ not_called1();
+ } else {
+ return baz();
+ not_called2();
+ }
+ function bar() { return 7; }
+ return not_reached;
+ function UnusedFunction() {}
+ function baz() { return 8; }
+ }
+ }
+ expect: {
+ function foo(x) {
+ return x ? bar() : baz();
+ function bar() { return 7 }
+ function baz() { return 8 }
+ }
+ }
+ expect_warnings: [
+ 'WARN: Dropping unreachable code [test/compress/issue-1034.js:11,16]',
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:14,16]",
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:17,12]",
+ "WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:18,21]"
+ ]
+}
+
+non_hoisted_function_after_return_2a: {
+ options = {
+ hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
+ evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
+ if_return: true, join_vars: true, cascade: true, side_effects: true,
+ collapse_vars: false
+ }
+ input: {
+ function foo(x) {
+ if (x) {
+ return bar(1);
+ var a = not_called(1);
+ } else {
+ return bar(2);
+ var b = not_called(2);
+ }
+ var c = bar(3);
+ function bar(x) { return 7 - x; }
+ function nope() {}
+ return b || c;
+ }
+ }
+ expect: {
+ // NOTE: Output is correct, but suboptimal. Not a regression. Can be improved in future.
+ // This output is run through non_hoisted_function_after_return_2b with same flags.
+ function foo(x) {
+ if (x) {
+ return bar(1);
+ } else {
+ return bar(2);
+ var b;
+ }
+ var c = bar(3);
+ function bar(x) {
+ return 7 - x;
+ }
+ return b || c;
+ }
+ }
+ expect_warnings: [
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:48,16]",
+ "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:48,16]",
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:51,16]",
+ "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
+ "WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
+ "WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]"
+ ]
+}
+
+non_hoisted_function_after_return_2b: {
+ options = {
+ hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
+ evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
+ if_return: true, join_vars: true, cascade: true, side_effects: true,
+ collapse_vars: false
+ }
+ input: {
+ // Note: output of test non_hoisted_function_after_return_2a run through compress again
+ function foo(x) {
+ if (x) {
+ return bar(1);
+ } else {
+ return bar(2);
+ var b;
+ }
+ var c = bar(3);
+ function bar(x) {
+ return 7 - x;
+ }
+ return b || c;
+ }
+ }
+ expect: {
+ // the output we would have liked to see from non_hoisted_function_after_return_2a
+ function foo(x) {
+ return bar(x ? 1 : 2);
+ function bar(x) { return 7 - x; }
+ }
+ }
+ expect_warnings: [
+ // Notice that some warnings are repeated by multiple compress passes.
+ // Not a regression. There is room for improvement here.
+ // Warnings should be cached and only output if unique.
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]",
+ "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]",
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]",
+ "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]",
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]",
+ "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]",
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]",
+ "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]",
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:102,12]",
+ "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:102,12]",
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:106,12]",
+ "WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]",
+ "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]",
+ "WARN: Dropping unused variable b [test/compress/issue-1034.js:100,20]",
+ "WARN: Dropping unused variable c [test/compress/issue-1034.js:102,16]"
+ ]
+}
+
diff --git a/test/run-tests.js b/test/run-tests.js
index fcb1b375..b4333b7a 100755
--- a/test/run-tests.js
+++ b/test/run-tests.js
@@ -88,6 +88,14 @@ function run_compress_tests() {
var options = U.defaults(test.options, {
warnings: false
});
+ var warnings_emitted = [];
+ var original_warn_function = U.AST_Node.warn_function;
+ if (test.expect_warnings) {
+ U.AST_Node.warn_function = function(text) {
+ warnings_emitted.push("WARN: " + text);
+ };
+ options.warnings = true;
+ }
var cmp = new U.Compressor(options, true);
var output_options = test.beautify || {};
var expect;
@@ -117,6 +125,24 @@ function run_compress_tests() {
failures++;
failed_files[file] = 1;
}
+ else if (test.expect_warnings) {
+ U.AST_Node.warn_function = original_warn_function;
+ var expected_warnings = make_code(test.expect_warnings, {
+ beautify: false,
+ quote_style: 2, // force double quote to match JSON
+ });
+ var actual_warnings = JSON.stringify(warnings_emitted);
+ actual_warnings = actual_warnings.split(process.cwd() + "/").join("");
+ if (expected_warnings != actual_warnings) {
+ log("!!! failed\n---INPUT---\n{input}\n---EXPECTED WARNINGS---\n{expected_warnings}\n---ACTUAL WARNINGS---\n{actual_warnings}\n\n", {
+ input: input_code,
+ expected_warnings: expected_warnings,
+ actual_warnings: actual_warnings,
+ });
+ failures++;
+ failed_files[file] = 1;
+ }
+ }
}
var tests = parse_test(path.resolve(dir, file));
for (var i in tests) if (tests.hasOwnProperty(i)) {
@@ -168,7 +194,7 @@ function parse_test(file) {
}
if (node instanceof U.AST_LabeledStatement) {
assert.ok(
- node.label.name == "input" || node.label.name == "expect" || node.label.name == "expect_exact",
+ ["input", "expect", "expect_exact", "expect_warnings"].indexOf(node.label.name) >= 0,
tmpl("Unsupported label {name} [{line},{col}]", {
name: node.label.name,
line: node.label.start.line,