JS(extractor): support optional chaining

This commit is contained in:
Esben Sparre Andreasen
2018-11-20 14:03:04 +01:00
parent 165bb8b6b8
commit 00587ba7b4
37 changed files with 4908 additions and 31 deletions

View File

@@ -215,6 +215,7 @@ public class AST2JSON extends DefaultVisitor<Void, JsonElement> {
JsonObject result = this.mkNode(nd);
result.add("callee", visit(nd.getCallee()));
result.add("arguments", visit(nd.getArguments()));
result.add("optional", new JsonPrimitive(nd.isOptional()));
return result;
}
@@ -424,6 +425,7 @@ public class AST2JSON extends DefaultVisitor<Void, JsonElement> {
result.add("object", visit(nd.getObject()));
result.add("property", visit(nd.getProperty()));
result.add("computed", new JsonPrimitive(nd.isComputed()));
result.add("optional", new JsonPrimitive(nd.isOptional()));
return result;
}

View File

@@ -8,8 +8,8 @@ import com.semmle.ts.ast.ITypeExpression;
* A function call expression such as <code>f(1, 1)</code>.
*/
public class CallExpression extends InvokeExpression {
public CallExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments) {
super("CallExpression", loc, callee, typeArguments, arguments);
public CallExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments, Boolean optional, Boolean onOptionalChain) {
super("CallExpression", loc, callee, typeArguments, arguments, optional, onOptionalChain);
}
@Override

View File

@@ -0,0 +1,16 @@
package com.semmle.js.ast;
/**
* A chainable expression, such as a member access or function call.
*/
public interface Chainable {
/**
* Is this step of the chain optional?
*/
abstract boolean isOptional();
/**
* Is this on an optional chain?
*/
abstract boolean isOnOptionalChain();
}

View File

@@ -8,20 +8,24 @@ import com.semmle.ts.ast.ITypeExpression;
/**
* An invocation, that is, either a {@link CallExpression} or a {@link NewExpression}.
*/
public abstract class InvokeExpression extends Expression implements INodeWithSymbol {
public abstract class InvokeExpression extends Expression implements INodeWithSymbol, Chainable {
private final Expression callee;
private final List<ITypeExpression> typeArguments;
private final List<Expression> arguments;
private final boolean optional;
private final boolean onOptionalChain;
private int resolvedSignatureId = -1;
private int overloadIndex = -1;
private int symbol = -1;
public InvokeExpression(String type, SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments,
List<Expression> arguments) {
List<Expression> arguments, Boolean optional, Boolean onOptionalChain) {
super(type, loc);
this.callee = callee;
this.typeArguments = typeArguments;
this.arguments = arguments;
this.optional = optional == Boolean.TRUE;
this.onOptionalChain = onOptionalChain == Boolean.TRUE;
}
/**
@@ -45,6 +49,16 @@ public abstract class InvokeExpression extends Expression implements INodeWithSy
return arguments;
}
@Override
public boolean isOptional() {
return optional;
}
@Override
public boolean isOnOptionalChain() {
return onOptionalChain;
}
public int getResolvedSignatureId() {
return resolvedSignatureId;
}
@@ -70,4 +84,4 @@ public abstract class InvokeExpression extends Expression implements INodeWithSy
public void setSymbol(int symbol) {
this.symbol = symbol;
}
}
}

View File

@@ -6,16 +6,20 @@ import com.semmle.ts.ast.ITypeExpression;
/**
* A member expression, either computed (<code>e[f]</code>) or static (<code>e.f</code>).
*/
public class MemberExpression extends Expression implements ITypeExpression, INodeWithSymbol {
public class MemberExpression extends Expression implements ITypeExpression, INodeWithSymbol, Chainable {
private final Expression object, property;
private final boolean computed;
private final boolean optional;
private final boolean onOptionalChain;
private int symbol = -1;
public MemberExpression(SourceLocation loc, Expression object, Expression property, Boolean computed) {
public MemberExpression(SourceLocation loc, Expression object, Expression property, Boolean computed, Boolean optional, Boolean onOptionalChain) {
super("MemberExpression", loc);
this.object = object;
this.property = property;
this.computed = computed == Boolean.TRUE;
this.optional = optional == Boolean.TRUE;
this.onOptionalChain = onOptionalChain == Boolean.TRUE;
}
@Override
@@ -45,6 +49,16 @@ public class MemberExpression extends Expression implements ITypeExpression, INo
return computed;
}
@Override
public boolean isOptional() {
return optional;
}
@Override
public boolean isOnOptionalChain() {
return onOptionalChain;
}
@Override
public int getSymbol() {
return symbol;

View File

@@ -9,7 +9,7 @@ import com.semmle.ts.ast.ITypeExpression;
*/
public class NewExpression extends InvokeExpression {
public NewExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments) {
super("NewExpression", loc, callee, typeArguments, arguments);
super("NewExpression", loc, callee, typeArguments, arguments, false, false);
}
@Override

View File

@@ -97,7 +97,7 @@ public class NodeCopier implements Visitor<Void, INode> {
@Override
public CallExpression visit(CallExpression nd, Void q) {
return new CallExpression(visit(nd.getLoc()), copy(nd.getCallee()), copy(nd.getTypeArguments()), copy(nd.getArguments()));
return new CallExpression(visit(nd.getLoc()), copy(nd.getCallee()), copy(nd.getTypeArguments()), copy(nd.getArguments()), nd.isOptional(), nd.isOnOptionalChain());
}
@Override
@@ -140,7 +140,7 @@ public class NodeCopier implements Visitor<Void, INode> {
@Override
public MemberExpression visit(MemberExpression nd, Void q) {
return new MemberExpression(visit(nd.getLoc()), copy(nd.getObject()), copy(nd.getProperty()), nd.isComputed());
return new MemberExpression(visit(nd.getLoc()), copy(nd.getObject()), copy(nd.getProperty()), nd.isComputed(), nd.isOptional(), nd.isOnOptionalChain());
}
@Override