Merge pull request #2715 from erik-krogh/PrivateFields

Approved by asgerf
This commit is contained in:
semmle-qlci
2020-02-05 10:20:28 +00:00
committed by GitHub
13 changed files with 231 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ import static com.semmle.jcorn.Whitespace.lineBreak;
import com.semmle.jcorn.Identifiers.Dialect;
import com.semmle.jcorn.Options.AllowReserved;
import com.semmle.jcorn.TokenType.Properties;
import com.semmle.js.ast.ArrayExpression;
import com.semmle.js.ast.ArrayPattern;
import com.semmle.js.ast.ArrowFunctionExpression;
@@ -44,6 +45,7 @@ import com.semmle.js.ast.INode;
import com.semmle.js.ast.IPattern;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.IfStatement;
import com.semmle.js.ast.FieldDefinition;
import com.semmle.js.ast.ImportDeclaration;
import com.semmle.js.ast.ImportDefaultSpecifier;
import com.semmle.js.ast.ImportNamespaceSpecifier;
@@ -124,6 +126,7 @@ public class Parser {
private boolean inModule;
protected boolean inFunction;
protected boolean inGenerator;
protected boolean inClass;
protected boolean inAsync;
protected boolean inTemplateElement;
protected int pos;
@@ -240,8 +243,8 @@ public class Parser {
// Used to signify the start of a potential arrow function
this.potentialArrowAt = -1;
// Flags to track whether we are in a function, a generator, an async function.
this.inFunction = this.inGenerator = this.inAsync = false;
// Flags to track whether we are in a function, a generator, an async function, a class.
this.inFunction = this.inGenerator = this.inAsync = this.inClass = false;
// Positions to delayed-check that yield/await does not exist in default parameters.
this.yieldPos = this.awaitPos = 0;
// Labels in scope.
@@ -651,6 +654,9 @@ public class Parser {
case 58:
++this.pos;
return this.finishToken(TokenType.colon);
case 35:
++this.pos;
return this.finishToken(TokenType.pound);
case 63:
return this.readToken_question();
@@ -2191,6 +2197,7 @@ public class Parser {
// identifiers.
protected Identifier parseIdent(boolean liberal) {
Position startLoc = this.startLoc;
boolean isPrivateField = liberal && this.eat(TokenType.pound);
if (liberal && this.options.allowReserved() == AllowReserved.NEVER) liberal = false;
String name = null;
if (this.type == TokenType.name) {
@@ -2199,9 +2206,9 @@ public class Parser {
&& (this.options.ecmaVersion() >= 6
|| inputSubstring(this.start, this.end).indexOf("\\") == -1))
this.raiseRecoverable(this.start, "The keyword '" + this.value + "' is reserved");
if (this.inGenerator && this.value.equals("yield"))
if (!isPrivateField && this.inGenerator && this.value.equals("yield"))
this.raiseRecoverable(this.start, "Can not use 'yield' as identifier inside a generator");
if (this.inAsync && this.value.equals("await"))
if (!isPrivateField && this.inAsync && this.value.equals("await"))
this.raiseRecoverable(
this.start, "Can not use 'await' as identifier inside an async function");
name = String.valueOf(this.value);
@@ -2213,6 +2220,12 @@ public class Parser {
this.unexpected();
}
this.next();
if (isPrivateField) {
if (!this.inClass) {
this.raiseRecoverable(this.start, "Cannot use private fields outside a class");
}
name = "#" + name;
}
Identifier node = new Identifier(new SourceLocation(startLoc), name);
return this.finishNode(node);
}
@@ -3127,6 +3140,8 @@ public class Parser {
// Parse a class declaration or literal (depending on the
// `isStatement` parameter).
protected Node parseClass(Position startLoc, boolean isStatement) {
boolean oldInClass = this.inClass;
this.inClass = true;
SourceLocation loc = new SourceLocation(startLoc);
this.next();
Identifier id = this.parseClassId(isStatement);
@@ -3145,6 +3160,8 @@ public class Parser {
Node node;
if (isStatement) node = new ClassDeclaration(loc, id, superClass, classBody);
else node = new ClassExpression(loc, id, superClass, classBody);
this.inClass = oldInClass;
return this.finishNode(node);
}
@@ -3221,6 +3238,9 @@ public class Parser {
if (pi.kind.equals("set") && node.getValue().hasRest())
this.raiseRecoverable(params.get(params.size() - 1), "Setter cannot use rest params");
}
if (pi.key instanceof Identifier && ((Identifier)pi.key).getName().startsWith("#")) {
raiseRecoverable(pi.key, "Only fields, not methods, can be declared private.");
}
return node;
}

View File

@@ -85,6 +85,7 @@ public class TokenType {
dot = new TokenType(new Properties(".")),
questiondot = new TokenType(new Properties("?.")),
question = new TokenType(new Properties("?").beforeExpr()),
pound = new TokenType(kw("#")),
arrow = new TokenType(new Properties("=>").beforeExpr()),
template = new TokenType(new Properties("template")),
invalidTemplate = new TokenType(new Properties("invalidTemplate")),