mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
JS(extractor): support optional chaining
This commit is contained in:
@@ -153,7 +153,7 @@ public class CustomParser extends FlowParser {
|
||||
Identifier name = this.parseIdent(true);
|
||||
this.expect(TokenType.parenL);
|
||||
List<Expression> args = this.parseExprList(TokenType.parenR, false, false, null);
|
||||
CallExpression node = new CallExpression(new SourceLocation(startLoc), name, new ArrayList<>(), args);
|
||||
CallExpression node = new CallExpression(new SourceLocation(startLoc), name, new ArrayList<>(), args, false, false);
|
||||
return this.finishNode(node);
|
||||
} else {
|
||||
return super.parseExprAtom(refDestructuringErrors);
|
||||
@@ -212,7 +212,7 @@ public class CustomParser extends FlowParser {
|
||||
* A.f = function f(...) { ... };
|
||||
*/
|
||||
SourceLocation memloc = new SourceLocation(iface.getName() + "::" + id.getName(), iface.getLoc().getStart(), id.getLoc().getEnd());
|
||||
MemberExpression mem = new MemberExpression(memloc, iface, new Identifier(id.getLoc(), id.getName()), false);
|
||||
MemberExpression mem = new MemberExpression(memloc, iface, new Identifier(id.getLoc(), id.getName()), false, false, false);
|
||||
AssignmentExpression assgn = new AssignmentExpression(result.getLoc(), "=", mem, ((FunctionDeclaration)result).asFunctionExpression());
|
||||
return new ExpressionStatement(result.getLoc(), assgn);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.semmle.js.ast.BlockStatement;
|
||||
import com.semmle.js.ast.BreakStatement;
|
||||
import com.semmle.js.ast.CallExpression;
|
||||
import com.semmle.js.ast.CatchClause;
|
||||
import com.semmle.js.ast.Chainable;
|
||||
import com.semmle.js.ast.ClassBody;
|
||||
import com.semmle.js.ast.ClassDeclaration;
|
||||
import com.semmle.js.ast.ClassExpression;
|
||||
@@ -504,6 +505,14 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private Token readToken_question() { // '?'
|
||||
int next = charAt(this.pos + 1);
|
||||
int next2 = charAt(this.pos + 2);
|
||||
if (this.options.esnext() && next == '.' && !('0' <= next2 && next2 <= '9')) // '?.', but not '?.X' where X is a digit
|
||||
return this.finishOp(TokenType.questiondot, 2);
|
||||
return this.finishOp(TokenType.question, 1);
|
||||
}
|
||||
|
||||
private Token readToken_slash() { // '/'
|
||||
int next = charAt(this.pos + 1);
|
||||
if (this.exprAllowed) {
|
||||
@@ -616,7 +625,7 @@ public class Parser {
|
||||
case 123: ++this.pos; return this.finishToken(TokenType.braceL);
|
||||
case 125: ++this.pos; return this.finishToken(TokenType.braceR);
|
||||
case 58: ++this.pos; return this.finishToken(TokenType.colon);
|
||||
case 63: ++this.pos; return this.finishToken(TokenType.question);
|
||||
case 63: return this.readToken_question();
|
||||
|
||||
case 96: // '`'
|
||||
if (this.options.ecmaVersion() < 6) break;
|
||||
@@ -1465,17 +1474,19 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOnOptionalChain(boolean optional, Expression base) {
|
||||
return optional || base instanceof Chainable && ((Chainable)base).isOnOptionalChain();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single subscript {@code s}; if more subscripts could follow, return {@code Pair.make(s, true},
|
||||
* otherwise return {@code Pair.make(s, false)}.
|
||||
*/
|
||||
protected Pair<Expression, Boolean> parseSubscript(final Expression base, Position startLoc, boolean noCalls) {
|
||||
boolean maybeAsyncArrow = this.options.ecmaVersion() >= 8 && base instanceof Identifier && "async".equals(((Identifier) base).getName()) && !this.canInsertSemicolon();
|
||||
if (this.eat(TokenType.dot)) {
|
||||
MemberExpression node = new MemberExpression(new SourceLocation(startLoc), base, this.parseIdent(true), false);
|
||||
return Pair.make(this.finishNode(node), true);
|
||||
} else if (this.eat(TokenType.bracketL)) {
|
||||
MemberExpression node = new MemberExpression(new SourceLocation(startLoc), base, this.parseExpression(false, null), true);
|
||||
boolean optional = this.eat(TokenType.questiondot);
|
||||
if (this.eat(TokenType.bracketL)) {
|
||||
MemberExpression node = new MemberExpression(new SourceLocation(startLoc), base, this.parseExpression(false, null), true, optional, isOnOptionalChain(optional, base));
|
||||
this.expect(TokenType.bracketR);
|
||||
return Pair.make(this.finishNode(node), true);
|
||||
} else if (!noCalls && this.eat(TokenType.parenL)) {
|
||||
@@ -1494,11 +1505,17 @@ public class Parser {
|
||||
this.checkExpressionErrors(refDestructuringErrors, true);
|
||||
if (oldYieldPos > 0) this.yieldPos = oldYieldPos;
|
||||
if (oldAwaitPos > 0) this.awaitPos = oldAwaitPos;
|
||||
CallExpression node = new CallExpression(new SourceLocation(startLoc), base, new ArrayList<>(), exprList);
|
||||
CallExpression node = new CallExpression(new SourceLocation(startLoc), base, new ArrayList<>(), exprList, optional, isOnOptionalChain(optional, base));
|
||||
return Pair.make(this.finishNode(node), true);
|
||||
} else if (this.type == TokenType.backQuote) {
|
||||
if (isOnOptionalChain(optional, base)) {
|
||||
this.raise(base, "An optional chain may not be used in a tagged template expression.");
|
||||
}
|
||||
TaggedTemplateExpression node = new TaggedTemplateExpression(new SourceLocation(startLoc), base, this.parseTemplate(true));
|
||||
return Pair.make(this.finishNode(node), true);
|
||||
} else if (optional || this.eat(TokenType.dot)) {
|
||||
MemberExpression node = new MemberExpression(new SourceLocation(startLoc), base, this.parseIdent(true), false, optional, isOnOptionalChain(optional, base));
|
||||
return Pair.make(this.finishNode(node), true);
|
||||
} else {
|
||||
return Pair.make(base, false);
|
||||
}
|
||||
@@ -1719,6 +1736,10 @@ public class Parser {
|
||||
int innerStartPos = this.start;
|
||||
Position innerStartLoc = this.startLoc;
|
||||
Expression callee = this.parseSubscripts(this.parseExprAtom(null), innerStartPos, innerStartLoc, true);
|
||||
|
||||
if (isOnOptionalChain(false, callee))
|
||||
this.raise(callee, "An optional chain may not be used in a `new` expression.");
|
||||
|
||||
List<Expression> arguments;
|
||||
if (this.eat(TokenType.parenL))
|
||||
arguments = this.parseExprList(TokenType.parenR, this.options.ecmaVersion() >= 8, false, null);
|
||||
@@ -2159,9 +2180,12 @@ public class Parser {
|
||||
return new ParenthesizedExpression(node.getLoc(), (Expression) this.toAssignable(expr, isBinding));
|
||||
}
|
||||
|
||||
if (node instanceof MemberExpression)
|
||||
if (node instanceof MemberExpression) {
|
||||
if (isOnOptionalChain(false, (MemberExpression)node))
|
||||
this.raise(node, "Invalid left-hand side in assignment");
|
||||
if (!isBinding)
|
||||
return node;
|
||||
}
|
||||
|
||||
this.raise(node, "Assigning to rvalue");
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ public class TokenType {
|
||||
semi = new TokenType(new Properties(";").beforeExpr()),
|
||||
colon = new TokenType(new Properties(":").beforeExpr()),
|
||||
dot = new TokenType(new Properties(".")),
|
||||
questiondot = new TokenType(new Properties("?.")),
|
||||
question = new TokenType(new Properties("?").beforeExpr()),
|
||||
arrow = new TokenType(new Properties("=>").beforeExpr()),
|
||||
template = new TokenType(new Properties("template")),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
16
javascript/extractor/src/com/semmle/js/ast/Chainable.java
Normal file
16
javascript/extractor/src/com/semmle/js/ast/Chainable.java
Normal 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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -405,6 +405,9 @@ public class ASTExtractor {
|
||||
if (nd.getOverloadIndex() != -1) {
|
||||
trapwriter.addTuple("invoke_expr_overload_index", key, nd.getOverloadIndex());
|
||||
}
|
||||
if (nd.isOptional()) {
|
||||
trapwriter.addTuple("isOptionalChaining", key);
|
||||
}
|
||||
emitNodeSymbol(nd, key);
|
||||
return key;
|
||||
}
|
||||
@@ -531,6 +534,9 @@ public class ASTExtractor {
|
||||
visit(nd.getObject(), key, 0, baseIdContext);
|
||||
visit(nd.getProperty(), key, 1, nd.isComputed() ? IdContext.varBind : IdContext.label);
|
||||
}
|
||||
if (nd.isOptional()) {
|
||||
trapwriter.addTuple("isOptionalChaining", key);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -1245,7 +1251,7 @@ public class ASTExtractor {
|
||||
Super superExpr = new Super(fakeLoc("super", loc));
|
||||
CallExpression superCall = new CallExpression(
|
||||
fakeLoc("super(...args)", loc),
|
||||
superExpr, new ArrayList<>(), CollectionUtil.makeList(spreadArgs));
|
||||
superExpr, new ArrayList<>(), CollectionUtil.makeList(spreadArgs), false, false);
|
||||
ExpressionStatement superCallStmt = new ExpressionStatement(
|
||||
fakeLoc("super(...args);", loc), superCall);
|
||||
body.getBody().add(superCallStmt);
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.semmle.js.ast.BlockStatement;
|
||||
import com.semmle.js.ast.BreakStatement;
|
||||
import com.semmle.js.ast.CallExpression;
|
||||
import com.semmle.js.ast.CatchClause;
|
||||
import com.semmle.js.ast.Chainable;
|
||||
import com.semmle.js.ast.ClassBody;
|
||||
import com.semmle.js.ast.ClassDeclaration;
|
||||
import com.semmle.js.ast.ClassExpression;
|
||||
@@ -776,6 +777,9 @@ public class CFGExtractor {
|
||||
// cache the set of normal control flow successors
|
||||
private final Map<Node, Object> followingCache = new LinkedHashMap<Node, Object>();
|
||||
|
||||
// map from a node in a chain of property accesses or calls to the successor info for the first node in the chain
|
||||
private final Map<Chainable, SuccessorInfo> chainRootSuccessors = new LinkedHashMap<Chainable, SuccessorInfo>();
|
||||
|
||||
/**
|
||||
* Generate entry node.
|
||||
*/
|
||||
@@ -1637,16 +1641,36 @@ public class CFGExtractor {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void preVisitChainable(Chainable chainable, Expression base, SuccessorInfo i) {
|
||||
if (!chainable.isOnOptionalChain()) // optimization: bookkeeping is only needed for optional chains
|
||||
return;
|
||||
// start of chain
|
||||
chainRootSuccessors.putIfAbsent(chainable, i);
|
||||
// next step in chain
|
||||
if (base instanceof Chainable)
|
||||
chainRootSuccessors.put((Chainable)base, chainRootSuccessors.get(chainable));
|
||||
}
|
||||
|
||||
private void postVisitChainable(Chainable chainable, Expression base, boolean optional) {
|
||||
if (optional) {
|
||||
succ(base, chainRootSuccessors.get(chainable).getSuccessors(false));
|
||||
}
|
||||
chainRootSuccessors.remove(chainable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(MemberExpression nd, SuccessorInfo i) {
|
||||
preVisitChainable(nd, nd.getObject(), i);
|
||||
seq(nd.getObject(), nd.getProperty(), nd);
|
||||
// property accesses may throw
|
||||
succ(nd, union(this.findTarget(JumpType.THROW, null), i.getGuardedSuccessors(nd)));
|
||||
postVisitChainable(nd, nd.getObject(), nd.isOptional());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(InvokeExpression nd, SuccessorInfo i) {
|
||||
preVisitChainable(nd, nd.getCallee(), i);
|
||||
seq(nd.getCallee(), nd.getArguments(), nd);
|
||||
Object succs = i.getGuardedSuccessors(nd);
|
||||
if (nd instanceof CallExpression && nd.getCallee() instanceof Super && !instanceFields.isEmpty()) {
|
||||
@@ -1660,6 +1684,7 @@ public class CFGExtractor {
|
||||
}
|
||||
// calls may throw
|
||||
succ(nd, union(this.findTarget(JumpType.THROW, null), succs));
|
||||
postVisitChainable(nd, nd.getCallee(), nd.isOptional());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class Main {
|
||||
* such a way that it may produce different tuples for the same file under the same
|
||||
* {@link ExtractorConfig}.
|
||||
*/
|
||||
public static final String EXTRACTOR_VERSION = "2018-11-12";
|
||||
public static final String EXTRACTOR_VERSION = "2018-11-20";
|
||||
|
||||
public static final Pattern NEWLINE = Pattern.compile("\n");
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ import java.io.File;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -40,7 +43,9 @@ public class TrapTests {
|
||||
List<Object[]> testData = new ArrayList<Object[]>();
|
||||
|
||||
// iterate over all test groups
|
||||
for (String testgroup : BASE.list()) {
|
||||
List<String> testGroups = Arrays.asList(BASE.list());
|
||||
testGroups.sort(Comparator.naturalOrder());
|
||||
for (String testgroup : testGroups) {
|
||||
File root = new File(BASE, testgroup);
|
||||
if (root.isDirectory()) {
|
||||
// check for options.json file and process it if it exists
|
||||
@@ -78,7 +83,9 @@ public class TrapTests {
|
||||
testData.add(new Object[] { testgroup, "tsconfig", new ArrayList<String>(options) });
|
||||
} else {
|
||||
// create isolated tests for each input file in the group
|
||||
for (String testfile : inputDir.list()) {
|
||||
List<String> tests = Arrays.asList(inputDir.list());
|
||||
tests.sort(Comparator.naturalOrder());
|
||||
for (String testfile : tests) {
|
||||
testData.add(new Object[] { testgroup, testfile, new ArrayList<String>(options) });
|
||||
}
|
||||
}
|
||||
@@ -149,7 +156,13 @@ public class TrapTests {
|
||||
// convert to and from UTF-8 to mimick treatment of unencodable characters
|
||||
byte[] actual_utf8_bytes = StringUtil.stringToBytes(sw.toString());
|
||||
String actual = new String(actual_utf8_bytes, Charset.forName("UTF-8"));
|
||||
String expected = new WholeIO().strictreadText(new File(outputDir, f.getName() + ".trap"));
|
||||
File trap = new File(outputDir, f.getName() + ".trap");
|
||||
boolean replaceExpectedOutput = false;
|
||||
if (replaceExpectedOutput) {
|
||||
System.out.println("Replacing expected output for " + trap);
|
||||
new WholeIO().strictwrite(trap, actual);
|
||||
}
|
||||
String expected = new WholeIO().strictreadText(trap);
|
||||
expectedVsActual.add(Pair.make(expected, actual));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -830,7 +830,7 @@ public class TypeScriptASTConverter {
|
||||
}
|
||||
Expression callee = convertChild(node, "expression");
|
||||
List<ITypeExpression> typeArguments = convertChildrenAsTypes(node, "typeArguments");
|
||||
CallExpression call = new CallExpression(loc, callee, typeArguments, arguments);
|
||||
CallExpression call = new CallExpression(loc, callee, typeArguments, arguments, false, false);
|
||||
attachResolvedSignature(call, node);
|
||||
return call;
|
||||
}
|
||||
@@ -1027,7 +1027,7 @@ public class TypeScriptASTConverter {
|
||||
SourceLocation loc) throws ParseError {
|
||||
Expression object = convertChild(node, "expression");
|
||||
Expression property = convertChild(node, "argumentExpression");
|
||||
return new MemberExpression(loc, object, property, true);
|
||||
return new MemberExpression(loc, object, property, true, false, false);
|
||||
}
|
||||
|
||||
private Node convertEmptyStatement(SourceLocation loc) {
|
||||
@@ -1311,7 +1311,7 @@ public class TypeScriptASTConverter {
|
||||
} else {
|
||||
throw new ParseError("Unsupported syntax in import type", getSourceLocation(node).getStart());
|
||||
}
|
||||
MemberExpression member = new MemberExpression(getSourceLocation(node), (Expression) base, name, false);
|
||||
MemberExpression member = new MemberExpression(getSourceLocation(node), (Expression) base, name, false, false, false);
|
||||
attachSymbolInformation(member, node);
|
||||
return member;
|
||||
}
|
||||
@@ -1797,7 +1797,7 @@ public class TypeScriptASTConverter {
|
||||
|
||||
private Node convertPropertyAccessExpression(JsonObject node,
|
||||
SourceLocation loc) throws ParseError {
|
||||
return new MemberExpression(loc, convertChild(node, "expression"), convertChild(node, "name"), false);
|
||||
return new MemberExpression(loc, convertChild(node, "expression"), convertChild(node, "name"), false, false, false);
|
||||
}
|
||||
|
||||
private Node convertPropertyAssignment(JsonObject node,
|
||||
@@ -1838,7 +1838,7 @@ public class TypeScriptASTConverter {
|
||||
}
|
||||
|
||||
private Node convertQualifiedName(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
MemberExpression expr = new MemberExpression(loc, convertChild(node, "left"), convertChild(node, "right"), false);
|
||||
MemberExpression expr = new MemberExpression(loc, convertChild(node, "left"), convertChild(node, "right"), false, false, false);
|
||||
attachSymbolInformation(expr, node);
|
||||
return expr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user