Make classes implicitly strict mode
This commit is contained in:
@@ -1292,12 +1292,15 @@ TreeWalker.prototype = {
|
|||||||
this.directives = Object.create(this.directives);
|
this.directives = Object.create(this.directives);
|
||||||
} else if (node instanceof AST_Directive) {
|
} else if (node instanceof AST_Directive) {
|
||||||
this.directives[node.value] = this.directives[node.value] ? "up" : true;
|
this.directives[node.value] = this.directives[node.value] ? "up" : true;
|
||||||
|
} else if (node instanceof AST_Class) {
|
||||||
|
this.directives = Object.create(this.directives);
|
||||||
|
this.directives["use strict"] = this.directives["use strict"] ? "up" : true;
|
||||||
}
|
}
|
||||||
this.stack.push(node);
|
this.stack.push(node);
|
||||||
},
|
},
|
||||||
pop: function(node) {
|
pop: function(node) {
|
||||||
this.stack.pop();
|
this.stack.pop();
|
||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Lambda || node instanceof AST_Class) {
|
||||||
this.directives = Object.getPrototypeOf(this.directives);
|
this.directives = Object.getPrototypeOf(this.directives);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2039,6 +2039,9 @@ function parse($TEXT, options) {
|
|||||||
function class_(KindOfClass) {
|
function class_(KindOfClass) {
|
||||||
var start, method, class_name, extends_, a = [];
|
var start, method, class_name, extends_, a = [];
|
||||||
|
|
||||||
|
S.input.push_directives_stack(); // Push directive stack, but not scope stack
|
||||||
|
S.input.add_directive("use strict");
|
||||||
|
|
||||||
if (S.token.type == "name" && S.token.value != "extends") {
|
if (S.token.type == "name" && S.token.value != "extends") {
|
||||||
class_name = as_symbol(KindOfClass === AST_DefClass ? AST_SymbolDefClass : AST_SymbolClass);
|
class_name = as_symbol(KindOfClass === AST_DefClass ? AST_SymbolDefClass : AST_SymbolClass);
|
||||||
}
|
}
|
||||||
@@ -2063,6 +2066,8 @@ function parse($TEXT, options) {
|
|||||||
if (is("punc", ";")) { next(); }
|
if (is("punc", ";")) { next(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S.input.pop_directives_stack();
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
|
||||||
return new KindOfClass({
|
return new KindOfClass({
|
||||||
|
|||||||
10
test/compress/directives.js
Normal file
10
test/compress/directives.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
class_directives_compression: {
|
||||||
|
input: {
|
||||||
|
class foo {
|
||||||
|
foo() {
|
||||||
|
"use strict";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: "class foo{foo(){}}"
|
||||||
|
}
|
||||||
@@ -120,7 +120,6 @@ yield_as_identifier_outside_strict_mode: {
|
|||||||
function foo(...yield){}
|
function foo(...yield){}
|
||||||
try { new Error("") } catch (yield) {}
|
try { new Error("") } catch (yield) {}
|
||||||
var yield = "foo";
|
var yield = "foo";
|
||||||
class yield {}
|
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
import yield from "bar";
|
import yield from "bar";
|
||||||
@@ -137,7 +136,6 @@ yield_as_identifier_outside_strict_mode: {
|
|||||||
function foo(...yield){}
|
function foo(...yield){}
|
||||||
try { new Error("") } catch (yield) {}
|
try { new Error("") } catch (yield) {}
|
||||||
var yield = "foo";
|
var yield = "foo";
|
||||||
class yield {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,10 +62,10 @@ describe("Directives", function() {
|
|||||||
it("Should know which strings are directive and which ones are not", function() {
|
it("Should know which strings are directive and which ones are not", function() {
|
||||||
var test_directive = function(tokenizer, test) {
|
var test_directive = function(tokenizer, test) {
|
||||||
test.directives.map(function(directive) {
|
test.directives.map(function(directive) {
|
||||||
assert.strictEqual(tokenizer.has_directive(directive), true, directive + " in " + test.input);
|
assert.strictEqual(tokenizer.has_directive(directive), true, "Didn't found directive `" + directive + "` at the end of `" + test.input + '`');
|
||||||
});
|
});
|
||||||
test.non_directives.map(function(fake_directive) {
|
test.non_directives.map(function(fake_directive) {
|
||||||
assert.strictEqual(tokenizer.has_directive(fake_directive), false, fake_directive + " in " + test.input);
|
assert.strictEqual(tokenizer.has_directive(fake_directive), false, "Unexpectedly found directive `" + fake_directive + "` at the end of `" + test.input + '`');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +156,16 @@ describe("Directives", function() {
|
|||||||
input: '"use strict";try{"use asm";',
|
input: '"use strict";try{"use asm";',
|
||||||
directives: ["use strict"],
|
directives: ["use strict"],
|
||||||
non_directives: ["use\nstrict", "use \nstrict", "use asm"]
|
non_directives: ["use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'class foo {',
|
||||||
|
directives: ["use strict"],
|
||||||
|
non_directives: ["use\nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'class foo {}',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use asm", "use\nstrict"]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -367,4 +377,44 @@ describe("Directives", function() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
it("Should be detect implicit usages of strict mode from tree walker", function() {
|
||||||
|
var tests = [
|
||||||
|
{
|
||||||
|
input: 'class foo {bar(){_check_}}',
|
||||||
|
directives: ["use strict"],
|
||||||
|
non_directives: ["use bar"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'class foo {bar(){}}_check_',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use bar"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
var checked;
|
||||||
|
var checkWalker = new uglify.TreeWalker(function(node, descend) {
|
||||||
|
if (node instanceof uglify.AST_Symbol && node.name === "_check_") {
|
||||||
|
checked = true;
|
||||||
|
for (var j = 0; j < tests[i].directives.length; j++) {
|
||||||
|
assert.equal(checkWalker.has_directive(tests[i].directives[j]), true,
|
||||||
|
"Did not found directive '" + tests[i].directives[j] + "' in test " + tests[i].input)
|
||||||
|
}
|
||||||
|
for (var k = 0; k < tests[i].non_directives.length; k++) {
|
||||||
|
assert.equal(checkWalker.has_directive(tests[i].non_directives[k]), undefined,
|
||||||
|
"Found directive '" + tests[i].non_directives[k] + "' in test " + tests[i].input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (; i < tests.length; i++) {
|
||||||
|
// Do tests - iterate the ast in each test - check only when _check_ occurs - fail when no _check_ has been found
|
||||||
|
checked = false;
|
||||||
|
var ast = uglify.parse(tests[i].input);
|
||||||
|
ast.walk(checkWalker);
|
||||||
|
if (!checked) {
|
||||||
|
throw "No _check_ symbol found in " + tests[i].input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user