Skip to content

Commit

Permalink
Disallow 'new.target' when not in a function.
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=172375523
  • Loading branch information
tbreisacher authored and lauraharker committed Oct 16, 2017
1 parent 25fb3d2 commit 120c76a
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 15 deletions.
19 changes: 16 additions & 3 deletions src/com/google/javascript/jscomp/parsing/IRFactory.java
Expand Up @@ -222,11 +222,11 @@ class IRFactory {

static final String UNEXPECTED_CONTINUE = "continue must be inside loop";

static final String UNEXPECTED_LABLED_CONTINUE =
static final String UNEXPECTED_LABELLED_CONTINUE =
"continue can only use labeles of iteration statements";

static final String UNEXPECTED_RETURN = "return must be inside function";

static final String UNEXPECTED_NEW_DOT_TARGET = "new.target must be inside a function";
static final String UNDEFINED_LABEL = "undefined label \"%s\"";

private final String sourceString;
Expand Down Expand Up @@ -433,6 +433,7 @@ private void validate(Node n) {
validateParameters(n);
validateBreakContinue(n);
validateReturn(n);
validateNewDotTarget(n);
validateLabel(n);
}

Expand All @@ -449,6 +450,18 @@ private void validateReturn(Node n) {
}
}

private void validateNewDotTarget(Node n) {
if (n.getToken() == Token.NEW_TARGET) {
Node parent = n;
while ((parent = parent.getParent()) != null) {
if (parent.isFunction()) {
return;
}
}
errorReporter.error(UNEXPECTED_NEW_DOT_TARGET, sourceName, n.getLineno(), n.getCharno());
}
}

private void validateBreakContinue(Node n) {
if (n.isBreak() || n.isContinue()) {
Node labelName = n.getFirstChild();
Expand All @@ -469,7 +482,7 @@ private void validateBreakContinue(Node n) {
if (n.isContinue() && !isContinueTarget(parent.getLastChild())) {
// report invalid continue target
errorReporter.error(
UNEXPECTED_LABLED_CONTINUE,
UNEXPECTED_LABELLED_CONTINUE,
sourceName,
n.getLineno(), n.getCharno());
}
Expand Down
13 changes: 9 additions & 4 deletions test/com/google/javascript/jscomp/CodePrinterTest.java
Expand Up @@ -2772,18 +2772,23 @@ public void testEs6ArrowFunctionSetsOriginalNameForArguments() {

public void testEs6NewTargetBare() {
languageMode = LanguageMode.ECMASCRIPT_2015;
assertPrintSame("new.target.prototype");
assertPrintSame("class C{constructor(){new.target.prototype}}");
}

public void testEs6NewTargetPrototype() {
languageMode = LanguageMode.ECMASCRIPT_2015;
assertPrintSame("var callable=Object.setPrototypeOf(obj,new.target.prototype)");
assertPrintSame(
"class C{constructor(){var callable=Object.setPrototypeOf(obj,new.target.prototype)}}");
}

public void testEs6NewTargetConditional() {
languageMode = LanguageMode.ECMASCRIPT_2015;
assertPrint("if (!new.target) throw 'Must be called with new!';",
"if(!new.target)throw\"Must be called with new!\";");
assertPrint(
LINE_JOINER.join(
"function f() {",
" if (!new.target) throw 'Must be called with new!';",
"}"),
"function f(){if(!new.target)throw\"Must be called with new!\";}");
}

public void testGoogScope() {
Expand Down
Expand Up @@ -257,6 +257,7 @@ public void testAnonymousSuper() {

public void testNewTarget() {
testError("function Foo() { new.target; }", CANNOT_CONVERT_YET);
testError("class Example { foo() { new.target; } }", CANNOT_CONVERT_YET);
}

public void testClassWithJsDoc() {
Expand Down
23 changes: 15 additions & 8 deletions test/com/google/javascript/jscomp/parsing/ParserTest.java
Expand Up @@ -57,7 +57,7 @@ public final class ParserTest extends BaseJSTypeTestCase {
private static final String UNEXPECTED_RETURN =
"return must be inside function";

private static final String UNEXPECTED_LABELED_CONTINUE =
private static final String UNEXPECTED_LABELLED_CONTINUE =
"continue can only use labeles of iteration statements";

private static final String UNDEFINED_LABEL = "undefined label";
Expand Down Expand Up @@ -220,7 +220,7 @@ public void testContinueToSwitchWithDefault() {
public void testContinueToLabelSwitch() {
parseError(
"while(1) {a: switch(1) {case(1): continue a; }}",
UNEXPECTED_LABELED_CONTINUE);
UNEXPECTED_LABELLED_CONTINUE);
}

public void testContinueOutsideSwitch() {
Expand Down Expand Up @@ -3058,20 +3058,27 @@ public void testNewTarget() {
mode = LanguageMode.ECMASCRIPT6;
strictMode = SLOPPY;

// TODO(bradfordcsmith): new.target in global scope should be a syntax error
parse("new.target;");
parseError("new.target;", "new.target must be inside a function");

parse("function f() { new.target; };");

mode = LanguageMode.ECMASCRIPT5;
mode = LanguageMode.ECMASCRIPT3;
parseWarning(
"function f() { new.target; }",
"class C { f() { new.target; } }",
getRequiresEs6Message(Feature.CLASSES),
getRequiresEs6Message(Feature.MEMBER_DECLARATIONS),
getRequiresEs6Message(Feature.NEW_TARGET));

mode = LanguageMode.ECMASCRIPT3;
mode = LanguageMode.ECMASCRIPT5;
parseWarning(
"function f() { new.target; }",
"class C { f() { new.target; } }",
getRequiresEs6Message(Feature.CLASSES),
getRequiresEs6Message(Feature.MEMBER_DECLARATIONS),
getRequiresEs6Message(Feature.NEW_TARGET));

mode = LanguageMode.ECMASCRIPT6;
expectFeatures(Feature.CLASSES, Feature.MEMBER_DECLARATIONS, Feature.NEW_TARGET);
parse("class C { f() { new.target; } }");
}

public void testNewDotSomethingInvalid() {
Expand Down

0 comments on commit 120c76a

Please sign in to comment.