8027302: Identifiers containing unicode escapes are not recognized as reserved words

Reviewed-by: jlaskey, sundar
This commit is contained in:
Hannes Wallnöfer 2017-10-13 17:25:12 +02:00
parent 7d50345d2d
commit 61995f03d4
6 changed files with 358 additions and 34 deletions

View file

@ -477,4 +477,14 @@ public final class IdentNode extends Expression implements PropertyKey, Function
public IdentNode setIsDestructuredParameter() {
return new IdentNode(this, name, type, flags | DESTRUCTURED_PARAMETER, programPoint, conversion);
}
/**
* Checks whether the source code for this ident contains a unicode escape sequence by comparing
* the length of its name with its length in source code.
*
* @return true if ident source contains a unicode escape sequence
*/
public boolean containsEscapes() {
return Token.descLength(getToken()) != name.length();
}
}

View file

@ -786,15 +786,9 @@ public class Lexer extends Scanner {
if (ch0 == '\\' && ch1 == 'u') {
skip(2);
final int ch = hexSequence(4, TokenType.IDENT);
if (isWhitespace((char)ch)) {
return null;
}
if (ch < 0) {
sb.append('\\');
sb.append('u');
} else {
sb.append((char)ch);
}
assert ! isWhitespace((char)ch);
assert ch >= 0;
sb.append((char)ch);
} else {
// Add regular character.
sb.append(ch0);
@ -994,9 +988,6 @@ public class Lexer extends Scanner {
if (ch0 == '\\') {
type = ESCSTRING;
skip(1);
if (! isEscapeCharacter(ch0)) {
error(Lexer.message("invalid.escape.char"), STRING, position, limit);
}
if (isEOL(ch0)) {
// Multiline string literal
skipEOL(false);
@ -1093,9 +1084,6 @@ public class Lexer extends Scanner {
} else if (ch0 == '\\') {
skip(1);
// EscapeSequence
if (!isEscapeCharacter(ch0)) {
error(Lexer.message("invalid.escape.char"), TEMPLATE, position, limit);
}
if (isEOL(ch0)) {
// LineContinuation
skipEOL(false);
@ -1114,16 +1102,6 @@ public class Lexer extends Scanner {
error(Lexer.message("missing.close.quote"), TEMPLATE, position, limit);
}
/**
* Is the given character a valid escape char after "\" ?
*
* @param ch character to be checked
* @return if the given character is valid after "\"
*/
protected boolean isEscapeCharacter(final char ch) {
return true;
}
/**
* Convert string to number.
*

View file

@ -1472,12 +1472,7 @@ public class Parser extends AbstractParser implements Loggable {
*/
private void verifyIdent(final IdentNode ident, final String contextString) {
verifyStrictIdent(ident, contextString);
if (isES6()) {
final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length());
if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) {
throw error(expectMessage(IDENT));
}
}
checkEscapedKeyword(ident);
}
/**
@ -1502,6 +1497,18 @@ public class Parser extends AbstractParser implements Loggable {
}
}
/**
* ES6 11.6.2: A code point in a ReservedWord cannot be expressed by a | UnicodeEscapeSequence.
*/
private void checkEscapedKeyword(final IdentNode ident) {
if (isES6() && ident.containsEscapes()) {
final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length());
if (tokenType != IDENT && !(tokenType.getKind() == TokenKind.FUTURESTRICT && !isStrictMode)) {
throw error(AbstractParser.message("keyword.escaped.character"), ident.getToken());
}
}
}
/*
* VariableStatement :
* var VariableDeclarationList ;
@ -2646,7 +2653,7 @@ public class Parser extends AbstractParser implements Loggable {
});
} else {
// ECMA 12.4.1 strict mode restrictions
verifyStrictIdent((IdentNode) exception, "catch argument");
verifyIdent((IdentNode) exception, "catch argument");
}
@ -2761,6 +2768,7 @@ public class Parser extends AbstractParser implements Loggable {
break;
}
detectSpecialProperty(ident);
checkEscapedKeyword(ident);
return ident;
case OCTAL_LEGACY:
if (isStrictMode) {
@ -3404,6 +3412,7 @@ public class Parser extends AbstractParser implements Loggable {
// Catch special functions.
if (lhs instanceof IdentNode) {
detectSpecialFunction((IdentNode)lhs);
checkEscapedKeyword((IdentNode)lhs);
}
lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
@ -3779,7 +3788,7 @@ public class Parser extends AbstractParser implements Loggable {
expect(IDENT);
}
name = getIdent();
verifyStrictIdent(name, "function name");
verifyIdent(name, "function name");
} else if (isStatement) {
// Nashorn extension: anonymous function statements.
// Do not allow anonymous function statement if extensions
@ -4871,7 +4880,7 @@ public class Parser extends AbstractParser implements Loggable {
final String contextString = "function parameter";
if (param instanceof IdentNode) {
final IdentNode ident = (IdentNode)param;
verifyStrictIdent(ident, contextString);
verifyIdent(ident, contextString);
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
if (currentFunction != null) {
currentFunction.addParameterBinding(ident);

View file

@ -62,6 +62,7 @@ parser.error.regex.syntax={0}
parser.error.trailing.comma.in.json=Trailing comma is not allowed in JSON
parser.error.missing.const.assignment=Missing assignment to constant "{0}"
parser.error.unterminated.template.expression=Expected } after expression in template literal
parser.error.keyword.escaped.character=Keyword must not contain escaped characters
# ES6 mode error messages
parser.error.multiple.constructors=Class contains more than one constructor