From c7801a939bfa499b6cbc0dbe5e32e2e730639799 Mon Sep 17 00:00:00 2001 From: Andrey Tarantsov <andrey@tarantsov.com> Date: Thu, 22 Nov 2012 16:33:23 +0700 Subject: [PATCH] Fix: instrumentation breaks "new(require('foo'))(args)" Fix a missing parenthesis when generating code for a new() statement applied to an expression, like the example: new(require('foo'))(args) which used to generate new require('foo')(args) resulting in the returned function being called without 'new'. I have no idea why on earth TOK_LP calls instrument_function_call; it seems to treat all parethesized expressions as function calls, but I didn't feel like investigating that. --- instrument-js.cpp | 13 +++++++--- .../javascript-new-indirect.js | 25 +++++++++++++++++++ tests/javascript/javascript-new-indirect.js | 5 ++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 tests/javascript.expected/javascript-new-indirect.js create mode 100644 tests/javascript/javascript-new-indirect.js diff --git a/instrument-js.cpp b/instrument-js.cpp index 7a1868a..2814b45 100644 --- a/instrument-js.cpp +++ b/instrument-js.cpp @@ -438,7 +438,7 @@ static void instrument_function(JSParseNode * node, Stream * f, int indent, enum Stream_write_char(f, '}'); } -static void instrument_function_call(JSParseNode * node, Stream * f) { +static void instrument_function_call(JSParseNode * node, Stream * f, bool parenthesize_for_new) { JSParseNode * function_node = node->pn_head; if (function_node->pn_type == TOK_FUNCTION) { JSObject * object = function_node->pn_funpob->object; @@ -455,7 +455,14 @@ static void instrument_function_call(JSParseNode * node, Stream * f) { return; } } + bool parenthesize_callee = parenthesize_for_new && (function_node->pn_type == TOK_LP); // e.g. new (require('foo'))() + if (parenthesize_callee) { + Stream_write_char(f, '('); + } output_expression(function_node, f, false); + if (parenthesize_callee) { + Stream_write_char(f, ')'); + } Stream_write_char(f, '('); for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) { if (p != node->pn_head->pn_next) { @@ -636,7 +643,7 @@ static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_ break; case TOK_NEW: Stream_write_string(f, "new "); - instrument_function_call(node, f); + instrument_function_call(node, f, true); break; case TOK_DELETE: Stream_write_string(f, "delete "); @@ -693,7 +700,7 @@ static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_ Stream_write_char(f, ']'); break; case TOK_LP: - instrument_function_call(node, f); + instrument_function_call(node, f, false); break; case TOK_RB: Stream_write_char(f, '['); diff --git a/tests/javascript.expected/javascript-new-indirect.js b/tests/javascript.expected/javascript-new-indirect.js new file mode 100644 index 0000000..38c8a4e --- /dev/null +++ b/tests/javascript.expected/javascript-new-indirect.js @@ -0,0 +1,25 @@ +/* automatically generated by JSCoverage - do not edit */ +if (typeof _$jscoverage === 'undefined') _$jscoverage = {}; +if (! _$jscoverage['javascript-new-indirect.js']) { + _$jscoverage['javascript-new-indirect.js'] = []; + _$jscoverage['javascript-new-indirect.js'][1] = 0; + _$jscoverage['javascript-new-indirect.js'][2] = 0; + _$jscoverage['javascript-new-indirect.js'][3] = 0; + _$jscoverage['javascript-new-indirect.js'][4] = 0; + _$jscoverage['javascript-new-indirect.js'][5] = 0; +} +_$jscoverage['javascript-new-indirect.js'][1]++; +function X() { +} +_$jscoverage['javascript-new-indirect.js'][2]++; +function y() { + _$jscoverage['javascript-new-indirect.js'][2]++; + return X; +} +_$jscoverage['javascript-new-indirect.js'][3]++; +x = new (y())(); +_$jscoverage['javascript-new-indirect.js'][4]++; +x = new (y())(1); +_$jscoverage['javascript-new-indirect.js'][5]++; +x = new (y())(1, 2); +_$jscoverage['javascript-new-indirect.js'].source = ["function X() {}","function y() { return X; }","x = new (y())();","x = new (y())(1);","x = new (y())(1, 2);"]; diff --git a/tests/javascript/javascript-new-indirect.js b/tests/javascript/javascript-new-indirect.js new file mode 100644 index 0000000..3fd43c1 --- /dev/null +++ b/tests/javascript/javascript-new-indirect.js @@ -0,0 +1,5 @@ +function X() {} +function y() { return X; } +x = new (y())(); +x = new (y())(1); +x = new (y())(1, 2);