mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
JS(extractor): support optional chaining
This commit is contained in:
@@ -24,3 +24,5 @@
|
||||
* The TypeScript compiler is now bundled with the distribution, and no longer needs to be installed manually.
|
||||
Should the compiler version need to be overridden, set the `SEMMLE_TYPESCRIPT_HOME` environment variable to
|
||||
point to an installation of the `typescript` NPM package.
|
||||
|
||||
* The extractor now supports [Optional Chaining](https://github.com/tc39/proposal-optional-chaining) expressions.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
13
javascript/extractor/tests/esnext/input/optional-chaining.js
Normal file
13
javascript/extractor/tests/esnext/input/optional-chaining.js
Normal file
@@ -0,0 +1,13 @@
|
||||
a1?.b1;
|
||||
|
||||
a2?.[x2];
|
||||
|
||||
a3?.b3();
|
||||
|
||||
a4?.();
|
||||
|
||||
o5?.3:2;
|
||||
|
||||
a6?.b6[x6].c6?.(y6).d6;
|
||||
|
||||
delete a?.b
|
||||
@@ -0,0 +1 @@
|
||||
new a?.();
|
||||
@@ -0,0 +1 @@
|
||||
a?.`{b}`;
|
||||
@@ -0,0 +1 @@
|
||||
new a?.b();
|
||||
@@ -0,0 +1 @@
|
||||
a?.b`{c}`;
|
||||
@@ -0,0 +1 @@
|
||||
a?.b = c;
|
||||
@@ -0,0 +1 @@
|
||||
new a.b?.c();
|
||||
@@ -0,0 +1,29 @@
|
||||
a?.b.c(++x).d;
|
||||
|
||||
a?.b[3].c?.(x).d;
|
||||
|
||||
(a?.b).c;
|
||||
|
||||
(a?.b.c).d;
|
||||
|
||||
a?.[b?.c?.d].e?.f;
|
||||
|
||||
a?.()[b?.().c?.().d].e?.().f;
|
||||
|
||||
if (a?.b) {
|
||||
true;
|
||||
} else {
|
||||
false;
|
||||
}
|
||||
|
||||
if (!a?.b) {
|
||||
true;
|
||||
} else {
|
||||
false;
|
||||
}
|
||||
|
||||
if (a?.b && c?.d) {
|
||||
true;
|
||||
} else {
|
||||
false;
|
||||
}
|
||||
@@ -0,0 +1,655 @@
|
||||
#10000=@"/optional-chaining.js;sourcefile"
|
||||
files(#10000,"/optional-chaining.js","optional-chaining","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,13,11"
|
||||
locations_default(#20002,#10000,1,1,13,11)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
stmts(#20003,2,#20001,0,"a1?.b1;")
|
||||
#20004=@"loc,{#10000},1,1,1,7"
|
||||
locations_default(#20004,#10000,1,1,1,7)
|
||||
hasLocation(#20003,#20004)
|
||||
stmtContainers(#20003,#20001)
|
||||
#20005=*
|
||||
exprs(#20005,14,#20003,0,"a1?.b1")
|
||||
#20006=@"loc,{#10000},1,1,1,6"
|
||||
locations_default(#20006,#10000,1,1,1,6)
|
||||
hasLocation(#20005,#20006)
|
||||
enclosingStmt(#20005,#20003)
|
||||
exprContainers(#20005,#20001)
|
||||
#20007=*
|
||||
exprs(#20007,79,#20005,0,"a1")
|
||||
#20008=@"loc,{#10000},1,1,1,2"
|
||||
locations_default(#20008,#10000,1,1,1,2)
|
||||
hasLocation(#20007,#20008)
|
||||
enclosingStmt(#20007,#20003)
|
||||
exprContainers(#20007,#20001)
|
||||
literals("a1","a1",#20007)
|
||||
#20009=@"var;{a1};{#20000}"
|
||||
variables(#20009,"a1",#20000)
|
||||
bind(#20007,#20009)
|
||||
#20010=*
|
||||
exprs(#20010,0,#20005,1,"b1")
|
||||
#20011=@"loc,{#10000},1,5,1,6"
|
||||
locations_default(#20011,#10000,1,5,1,6)
|
||||
hasLocation(#20010,#20011)
|
||||
enclosingStmt(#20010,#20003)
|
||||
exprContainers(#20010,#20001)
|
||||
literals("b1","b1",#20010)
|
||||
isOptionalChaining(#20005)
|
||||
#20012=*
|
||||
stmts(#20012,2,#20001,1,"a2?.[x2];")
|
||||
#20013=@"loc,{#10000},3,1,3,9"
|
||||
locations_default(#20013,#10000,3,1,3,9)
|
||||
hasLocation(#20012,#20013)
|
||||
stmtContainers(#20012,#20001)
|
||||
#20014=*
|
||||
exprs(#20014,15,#20012,0,"a2?.[x2]")
|
||||
#20015=@"loc,{#10000},3,1,3,8"
|
||||
locations_default(#20015,#10000,3,1,3,8)
|
||||
hasLocation(#20014,#20015)
|
||||
enclosingStmt(#20014,#20012)
|
||||
exprContainers(#20014,#20001)
|
||||
#20016=*
|
||||
exprs(#20016,79,#20014,0,"a2")
|
||||
#20017=@"loc,{#10000},3,1,3,2"
|
||||
locations_default(#20017,#10000,3,1,3,2)
|
||||
hasLocation(#20016,#20017)
|
||||
enclosingStmt(#20016,#20012)
|
||||
exprContainers(#20016,#20001)
|
||||
literals("a2","a2",#20016)
|
||||
#20018=@"var;{a2};{#20000}"
|
||||
variables(#20018,"a2",#20000)
|
||||
bind(#20016,#20018)
|
||||
#20019=*
|
||||
exprs(#20019,79,#20014,1,"x2")
|
||||
#20020=@"loc,{#10000},3,6,3,7"
|
||||
locations_default(#20020,#10000,3,6,3,7)
|
||||
hasLocation(#20019,#20020)
|
||||
enclosingStmt(#20019,#20012)
|
||||
exprContainers(#20019,#20001)
|
||||
literals("x2","x2",#20019)
|
||||
#20021=@"var;{x2};{#20000}"
|
||||
variables(#20021,"x2",#20000)
|
||||
bind(#20019,#20021)
|
||||
isOptionalChaining(#20014)
|
||||
#20022=*
|
||||
stmts(#20022,2,#20001,2,"a3?.b3();")
|
||||
#20023=@"loc,{#10000},5,1,5,9"
|
||||
locations_default(#20023,#10000,5,1,5,9)
|
||||
hasLocation(#20022,#20023)
|
||||
stmtContainers(#20022,#20001)
|
||||
#20024=*
|
||||
exprs(#20024,13,#20022,0,"a3?.b3()")
|
||||
#20025=@"loc,{#10000},5,1,5,8"
|
||||
locations_default(#20025,#10000,5,1,5,8)
|
||||
hasLocation(#20024,#20025)
|
||||
enclosingStmt(#20024,#20022)
|
||||
exprContainers(#20024,#20001)
|
||||
#20026=*
|
||||
exprs(#20026,14,#20024,-1,"a3?.b3")
|
||||
#20027=@"loc,{#10000},5,1,5,6"
|
||||
locations_default(#20027,#10000,5,1,5,6)
|
||||
hasLocation(#20026,#20027)
|
||||
enclosingStmt(#20026,#20022)
|
||||
exprContainers(#20026,#20001)
|
||||
#20028=*
|
||||
exprs(#20028,79,#20026,0,"a3")
|
||||
#20029=@"loc,{#10000},5,1,5,2"
|
||||
locations_default(#20029,#10000,5,1,5,2)
|
||||
hasLocation(#20028,#20029)
|
||||
enclosingStmt(#20028,#20022)
|
||||
exprContainers(#20028,#20001)
|
||||
literals("a3","a3",#20028)
|
||||
#20030=@"var;{a3};{#20000}"
|
||||
variables(#20030,"a3",#20000)
|
||||
bind(#20028,#20030)
|
||||
#20031=*
|
||||
exprs(#20031,0,#20026,1,"b3")
|
||||
#20032=@"loc,{#10000},5,5,5,6"
|
||||
locations_default(#20032,#10000,5,5,5,6)
|
||||
hasLocation(#20031,#20032)
|
||||
enclosingStmt(#20031,#20022)
|
||||
exprContainers(#20031,#20001)
|
||||
literals("b3","b3",#20031)
|
||||
isOptionalChaining(#20026)
|
||||
#20033=*
|
||||
stmts(#20033,2,#20001,3,"a4?.();")
|
||||
#20034=@"loc,{#10000},7,1,7,7"
|
||||
locations_default(#20034,#10000,7,1,7,7)
|
||||
hasLocation(#20033,#20034)
|
||||
stmtContainers(#20033,#20001)
|
||||
#20035=*
|
||||
exprs(#20035,13,#20033,0,"a4?.()")
|
||||
#20036=@"loc,{#10000},7,1,7,6"
|
||||
locations_default(#20036,#10000,7,1,7,6)
|
||||
hasLocation(#20035,#20036)
|
||||
enclosingStmt(#20035,#20033)
|
||||
exprContainers(#20035,#20001)
|
||||
#20037=*
|
||||
exprs(#20037,79,#20035,-1,"a4")
|
||||
#20038=@"loc,{#10000},7,1,7,2"
|
||||
locations_default(#20038,#10000,7,1,7,2)
|
||||
hasLocation(#20037,#20038)
|
||||
enclosingStmt(#20037,#20033)
|
||||
exprContainers(#20037,#20001)
|
||||
literals("a4","a4",#20037)
|
||||
#20039=@"var;{a4};{#20000}"
|
||||
variables(#20039,"a4",#20000)
|
||||
bind(#20037,#20039)
|
||||
isOptionalChaining(#20035)
|
||||
#20040=*
|
||||
stmts(#20040,2,#20001,4,"o5?.3:2;")
|
||||
#20041=@"loc,{#10000},9,1,9,8"
|
||||
locations_default(#20041,#10000,9,1,9,8)
|
||||
hasLocation(#20040,#20041)
|
||||
stmtContainers(#20040,#20001)
|
||||
#20042=*
|
||||
exprs(#20042,11,#20040,0,"o5?.3:2")
|
||||
#20043=@"loc,{#10000},9,1,9,7"
|
||||
locations_default(#20043,#10000,9,1,9,7)
|
||||
hasLocation(#20042,#20043)
|
||||
enclosingStmt(#20042,#20040)
|
||||
exprContainers(#20042,#20001)
|
||||
#20044=*
|
||||
exprs(#20044,79,#20042,0,"o5")
|
||||
#20045=@"loc,{#10000},9,1,9,2"
|
||||
locations_default(#20045,#10000,9,1,9,2)
|
||||
hasLocation(#20044,#20045)
|
||||
enclosingStmt(#20044,#20040)
|
||||
exprContainers(#20044,#20001)
|
||||
literals("o5","o5",#20044)
|
||||
#20046=@"var;{o5};{#20000}"
|
||||
variables(#20046,"o5",#20000)
|
||||
bind(#20044,#20046)
|
||||
#20047=*
|
||||
exprs(#20047,3,#20042,1,".3")
|
||||
#20048=@"loc,{#10000},9,4,9,5"
|
||||
locations_default(#20048,#10000,9,4,9,5)
|
||||
hasLocation(#20047,#20048)
|
||||
enclosingStmt(#20047,#20040)
|
||||
exprContainers(#20047,#20001)
|
||||
literals("0.3",".3",#20047)
|
||||
#20049=*
|
||||
exprs(#20049,3,#20042,2,"2")
|
||||
#20050=@"loc,{#10000},9,7,9,7"
|
||||
locations_default(#20050,#10000,9,7,9,7)
|
||||
hasLocation(#20049,#20050)
|
||||
enclosingStmt(#20049,#20040)
|
||||
exprContainers(#20049,#20001)
|
||||
literals("2","2",#20049)
|
||||
#20051=*
|
||||
stmts(#20051,2,#20001,5,"a6?.b6[ ... y6).d6;")
|
||||
#20052=@"loc,{#10000},11,1,11,23"
|
||||
locations_default(#20052,#10000,11,1,11,23)
|
||||
hasLocation(#20051,#20052)
|
||||
stmtContainers(#20051,#20001)
|
||||
#20053=*
|
||||
exprs(#20053,14,#20051,0,"a6?.b6[ ... (y6).d6")
|
||||
#20054=@"loc,{#10000},11,1,11,22"
|
||||
locations_default(#20054,#10000,11,1,11,22)
|
||||
hasLocation(#20053,#20054)
|
||||
enclosingStmt(#20053,#20051)
|
||||
exprContainers(#20053,#20001)
|
||||
#20055=*
|
||||
exprs(#20055,13,#20053,0,"a6?.b6[x6].c6?.(y6)")
|
||||
#20056=@"loc,{#10000},11,1,11,19"
|
||||
locations_default(#20056,#10000,11,1,11,19)
|
||||
hasLocation(#20055,#20056)
|
||||
enclosingStmt(#20055,#20051)
|
||||
exprContainers(#20055,#20001)
|
||||
#20057=*
|
||||
exprs(#20057,14,#20055,-1,"a6?.b6[x6].c6")
|
||||
#20058=@"loc,{#10000},11,1,11,13"
|
||||
locations_default(#20058,#10000,11,1,11,13)
|
||||
hasLocation(#20057,#20058)
|
||||
enclosingStmt(#20057,#20051)
|
||||
exprContainers(#20057,#20001)
|
||||
#20059=*
|
||||
exprs(#20059,15,#20057,0,"a6?.b6[x6]")
|
||||
#20060=@"loc,{#10000},11,1,11,10"
|
||||
locations_default(#20060,#10000,11,1,11,10)
|
||||
hasLocation(#20059,#20060)
|
||||
enclosingStmt(#20059,#20051)
|
||||
exprContainers(#20059,#20001)
|
||||
#20061=*
|
||||
exprs(#20061,14,#20059,0,"a6?.b6")
|
||||
#20062=@"loc,{#10000},11,1,11,6"
|
||||
locations_default(#20062,#10000,11,1,11,6)
|
||||
hasLocation(#20061,#20062)
|
||||
enclosingStmt(#20061,#20051)
|
||||
exprContainers(#20061,#20001)
|
||||
#20063=*
|
||||
exprs(#20063,79,#20061,0,"a6")
|
||||
#20064=@"loc,{#10000},11,1,11,2"
|
||||
locations_default(#20064,#10000,11,1,11,2)
|
||||
hasLocation(#20063,#20064)
|
||||
enclosingStmt(#20063,#20051)
|
||||
exprContainers(#20063,#20001)
|
||||
literals("a6","a6",#20063)
|
||||
#20065=@"var;{a6};{#20000}"
|
||||
variables(#20065,"a6",#20000)
|
||||
bind(#20063,#20065)
|
||||
#20066=*
|
||||
exprs(#20066,0,#20061,1,"b6")
|
||||
#20067=@"loc,{#10000},11,5,11,6"
|
||||
locations_default(#20067,#10000,11,5,11,6)
|
||||
hasLocation(#20066,#20067)
|
||||
enclosingStmt(#20066,#20051)
|
||||
exprContainers(#20066,#20001)
|
||||
literals("b6","b6",#20066)
|
||||
isOptionalChaining(#20061)
|
||||
#20068=*
|
||||
exprs(#20068,79,#20059,1,"x6")
|
||||
#20069=@"loc,{#10000},11,8,11,9"
|
||||
locations_default(#20069,#10000,11,8,11,9)
|
||||
hasLocation(#20068,#20069)
|
||||
enclosingStmt(#20068,#20051)
|
||||
exprContainers(#20068,#20001)
|
||||
literals("x6","x6",#20068)
|
||||
#20070=@"var;{x6};{#20000}"
|
||||
variables(#20070,"x6",#20000)
|
||||
bind(#20068,#20070)
|
||||
#20071=*
|
||||
exprs(#20071,0,#20057,1,"c6")
|
||||
#20072=@"loc,{#10000},11,12,11,13"
|
||||
locations_default(#20072,#10000,11,12,11,13)
|
||||
hasLocation(#20071,#20072)
|
||||
enclosingStmt(#20071,#20051)
|
||||
exprContainers(#20071,#20001)
|
||||
literals("c6","c6",#20071)
|
||||
#20073=*
|
||||
exprs(#20073,79,#20055,0,"y6")
|
||||
#20074=@"loc,{#10000},11,17,11,18"
|
||||
locations_default(#20074,#10000,11,17,11,18)
|
||||
hasLocation(#20073,#20074)
|
||||
enclosingStmt(#20073,#20051)
|
||||
exprContainers(#20073,#20001)
|
||||
literals("y6","y6",#20073)
|
||||
#20075=@"var;{y6};{#20000}"
|
||||
variables(#20075,"y6",#20000)
|
||||
bind(#20073,#20075)
|
||||
isOptionalChaining(#20055)
|
||||
#20076=*
|
||||
exprs(#20076,0,#20053,1,"d6")
|
||||
#20077=@"loc,{#10000},11,21,11,22"
|
||||
locations_default(#20077,#10000,11,21,11,22)
|
||||
hasLocation(#20076,#20077)
|
||||
enclosingStmt(#20076,#20051)
|
||||
exprContainers(#20076,#20001)
|
||||
literals("d6","d6",#20076)
|
||||
#20078=*
|
||||
stmts(#20078,2,#20001,6,"delete a?.b")
|
||||
#20079=@"loc,{#10000},13,1,13,11"
|
||||
locations_default(#20079,#10000,13,1,13,11)
|
||||
hasLocation(#20078,#20079)
|
||||
stmtContainers(#20078,#20001)
|
||||
#20080=*
|
||||
exprs(#20080,22,#20078,0,"delete a?.b")
|
||||
hasLocation(#20080,#20079)
|
||||
enclosingStmt(#20080,#20078)
|
||||
exprContainers(#20080,#20001)
|
||||
#20081=*
|
||||
exprs(#20081,14,#20080,0,"a?.b")
|
||||
#20082=@"loc,{#10000},13,8,13,11"
|
||||
locations_default(#20082,#10000,13,8,13,11)
|
||||
hasLocation(#20081,#20082)
|
||||
enclosingStmt(#20081,#20078)
|
||||
exprContainers(#20081,#20001)
|
||||
#20083=*
|
||||
exprs(#20083,79,#20081,0,"a")
|
||||
#20084=@"loc,{#10000},13,8,13,8"
|
||||
locations_default(#20084,#10000,13,8,13,8)
|
||||
hasLocation(#20083,#20084)
|
||||
enclosingStmt(#20083,#20078)
|
||||
exprContainers(#20083,#20001)
|
||||
literals("a","a",#20083)
|
||||
#20085=@"var;{a};{#20000}"
|
||||
variables(#20085,"a",#20000)
|
||||
bind(#20083,#20085)
|
||||
#20086=*
|
||||
exprs(#20086,0,#20081,1,"b")
|
||||
#20087=@"loc,{#10000},13,11,13,11"
|
||||
locations_default(#20087,#10000,13,11,13,11)
|
||||
hasLocation(#20086,#20087)
|
||||
enclosingStmt(#20086,#20078)
|
||||
exprContainers(#20086,#20001)
|
||||
literals("b","b",#20086)
|
||||
isOptionalChaining(#20081)
|
||||
#20088=*
|
||||
lines(#20088,#20001,"a1?.b1;","
|
||||
")
|
||||
hasLocation(#20088,#20004)
|
||||
#20089=*
|
||||
lines(#20089,#20001,"","
|
||||
")
|
||||
#20090=@"loc,{#10000},2,1,2,0"
|
||||
locations_default(#20090,#10000,2,1,2,0)
|
||||
hasLocation(#20089,#20090)
|
||||
#20091=*
|
||||
lines(#20091,#20001,"a2?.[x2];","
|
||||
")
|
||||
hasLocation(#20091,#20013)
|
||||
#20092=*
|
||||
lines(#20092,#20001,"","
|
||||
")
|
||||
#20093=@"loc,{#10000},4,1,4,0"
|
||||
locations_default(#20093,#10000,4,1,4,0)
|
||||
hasLocation(#20092,#20093)
|
||||
#20094=*
|
||||
lines(#20094,#20001,"a3?.b3();","
|
||||
")
|
||||
hasLocation(#20094,#20023)
|
||||
#20095=*
|
||||
lines(#20095,#20001,"","
|
||||
")
|
||||
#20096=@"loc,{#10000},6,1,6,0"
|
||||
locations_default(#20096,#10000,6,1,6,0)
|
||||
hasLocation(#20095,#20096)
|
||||
#20097=*
|
||||
lines(#20097,#20001,"a4?.();","
|
||||
")
|
||||
hasLocation(#20097,#20034)
|
||||
#20098=*
|
||||
lines(#20098,#20001,"","
|
||||
")
|
||||
#20099=@"loc,{#10000},8,1,8,0"
|
||||
locations_default(#20099,#10000,8,1,8,0)
|
||||
hasLocation(#20098,#20099)
|
||||
#20100=*
|
||||
lines(#20100,#20001,"o5?.3:2;","
|
||||
")
|
||||
hasLocation(#20100,#20041)
|
||||
#20101=*
|
||||
lines(#20101,#20001,"","
|
||||
")
|
||||
#20102=@"loc,{#10000},10,1,10,0"
|
||||
locations_default(#20102,#10000,10,1,10,0)
|
||||
hasLocation(#20101,#20102)
|
||||
#20103=*
|
||||
lines(#20103,#20001,"a6?.b6[x6].c6?.(y6).d6;","
|
||||
")
|
||||
hasLocation(#20103,#20052)
|
||||
#20104=*
|
||||
lines(#20104,#20001,"","
|
||||
")
|
||||
#20105=@"loc,{#10000},12,1,12,0"
|
||||
locations_default(#20105,#10000,12,1,12,0)
|
||||
hasLocation(#20104,#20105)
|
||||
#20106=*
|
||||
lines(#20106,#20001,"delete a?.b","")
|
||||
hasLocation(#20106,#20079)
|
||||
numlines(#20001,13,7,0)
|
||||
#20107=*
|
||||
tokeninfo(#20107,6,#20001,0,"a1")
|
||||
hasLocation(#20107,#20008)
|
||||
#20108=*
|
||||
tokeninfo(#20108,8,#20001,1,"?.")
|
||||
#20109=@"loc,{#10000},1,3,1,4"
|
||||
locations_default(#20109,#10000,1,3,1,4)
|
||||
hasLocation(#20108,#20109)
|
||||
#20110=*
|
||||
tokeninfo(#20110,6,#20001,2,"b1")
|
||||
hasLocation(#20110,#20011)
|
||||
#20111=*
|
||||
tokeninfo(#20111,8,#20001,3,";")
|
||||
#20112=@"loc,{#10000},1,7,1,7"
|
||||
locations_default(#20112,#10000,1,7,1,7)
|
||||
hasLocation(#20111,#20112)
|
||||
#20113=*
|
||||
tokeninfo(#20113,6,#20001,4,"a2")
|
||||
hasLocation(#20113,#20017)
|
||||
#20114=*
|
||||
tokeninfo(#20114,8,#20001,5,"?.")
|
||||
#20115=@"loc,{#10000},3,3,3,4"
|
||||
locations_default(#20115,#10000,3,3,3,4)
|
||||
hasLocation(#20114,#20115)
|
||||
#20116=*
|
||||
tokeninfo(#20116,8,#20001,6,"[")
|
||||
#20117=@"loc,{#10000},3,5,3,5"
|
||||
locations_default(#20117,#10000,3,5,3,5)
|
||||
hasLocation(#20116,#20117)
|
||||
#20118=*
|
||||
tokeninfo(#20118,6,#20001,7,"x2")
|
||||
hasLocation(#20118,#20020)
|
||||
#20119=*
|
||||
tokeninfo(#20119,8,#20001,8,"]")
|
||||
#20120=@"loc,{#10000},3,8,3,8"
|
||||
locations_default(#20120,#10000,3,8,3,8)
|
||||
hasLocation(#20119,#20120)
|
||||
#20121=*
|
||||
tokeninfo(#20121,8,#20001,9,";")
|
||||
#20122=@"loc,{#10000},3,9,3,9"
|
||||
locations_default(#20122,#10000,3,9,3,9)
|
||||
hasLocation(#20121,#20122)
|
||||
#20123=*
|
||||
tokeninfo(#20123,6,#20001,10,"a3")
|
||||
hasLocation(#20123,#20029)
|
||||
#20124=*
|
||||
tokeninfo(#20124,8,#20001,11,"?.")
|
||||
#20125=@"loc,{#10000},5,3,5,4"
|
||||
locations_default(#20125,#10000,5,3,5,4)
|
||||
hasLocation(#20124,#20125)
|
||||
#20126=*
|
||||
tokeninfo(#20126,6,#20001,12,"b3")
|
||||
hasLocation(#20126,#20032)
|
||||
#20127=*
|
||||
tokeninfo(#20127,8,#20001,13,"(")
|
||||
#20128=@"loc,{#10000},5,7,5,7"
|
||||
locations_default(#20128,#10000,5,7,5,7)
|
||||
hasLocation(#20127,#20128)
|
||||
#20129=*
|
||||
tokeninfo(#20129,8,#20001,14,")")
|
||||
#20130=@"loc,{#10000},5,8,5,8"
|
||||
locations_default(#20130,#10000,5,8,5,8)
|
||||
hasLocation(#20129,#20130)
|
||||
#20131=*
|
||||
tokeninfo(#20131,8,#20001,15,";")
|
||||
#20132=@"loc,{#10000},5,9,5,9"
|
||||
locations_default(#20132,#10000,5,9,5,9)
|
||||
hasLocation(#20131,#20132)
|
||||
#20133=*
|
||||
tokeninfo(#20133,6,#20001,16,"a4")
|
||||
hasLocation(#20133,#20038)
|
||||
#20134=*
|
||||
tokeninfo(#20134,8,#20001,17,"?.")
|
||||
#20135=@"loc,{#10000},7,3,7,4"
|
||||
locations_default(#20135,#10000,7,3,7,4)
|
||||
hasLocation(#20134,#20135)
|
||||
#20136=*
|
||||
tokeninfo(#20136,8,#20001,18,"(")
|
||||
#20137=@"loc,{#10000},7,5,7,5"
|
||||
locations_default(#20137,#10000,7,5,7,5)
|
||||
hasLocation(#20136,#20137)
|
||||
#20138=*
|
||||
tokeninfo(#20138,8,#20001,19,")")
|
||||
#20139=@"loc,{#10000},7,6,7,6"
|
||||
locations_default(#20139,#10000,7,6,7,6)
|
||||
hasLocation(#20138,#20139)
|
||||
#20140=*
|
||||
tokeninfo(#20140,8,#20001,20,";")
|
||||
#20141=@"loc,{#10000},7,7,7,7"
|
||||
locations_default(#20141,#10000,7,7,7,7)
|
||||
hasLocation(#20140,#20141)
|
||||
#20142=*
|
||||
tokeninfo(#20142,6,#20001,21,"o5")
|
||||
hasLocation(#20142,#20045)
|
||||
#20143=*
|
||||
tokeninfo(#20143,8,#20001,22,"?")
|
||||
#20144=@"loc,{#10000},9,3,9,3"
|
||||
locations_default(#20144,#10000,9,3,9,3)
|
||||
hasLocation(#20143,#20144)
|
||||
#20145=*
|
||||
tokeninfo(#20145,3,#20001,23,".3")
|
||||
hasLocation(#20145,#20048)
|
||||
#20146=*
|
||||
tokeninfo(#20146,8,#20001,24,":")
|
||||
#20147=@"loc,{#10000},9,6,9,6"
|
||||
locations_default(#20147,#10000,9,6,9,6)
|
||||
hasLocation(#20146,#20147)
|
||||
#20148=*
|
||||
tokeninfo(#20148,3,#20001,25,"2")
|
||||
hasLocation(#20148,#20050)
|
||||
#20149=*
|
||||
tokeninfo(#20149,8,#20001,26,";")
|
||||
#20150=@"loc,{#10000},9,8,9,8"
|
||||
locations_default(#20150,#10000,9,8,9,8)
|
||||
hasLocation(#20149,#20150)
|
||||
#20151=*
|
||||
tokeninfo(#20151,6,#20001,27,"a6")
|
||||
hasLocation(#20151,#20064)
|
||||
#20152=*
|
||||
tokeninfo(#20152,8,#20001,28,"?.")
|
||||
#20153=@"loc,{#10000},11,3,11,4"
|
||||
locations_default(#20153,#10000,11,3,11,4)
|
||||
hasLocation(#20152,#20153)
|
||||
#20154=*
|
||||
tokeninfo(#20154,6,#20001,29,"b6")
|
||||
hasLocation(#20154,#20067)
|
||||
#20155=*
|
||||
tokeninfo(#20155,8,#20001,30,"[")
|
||||
#20156=@"loc,{#10000},11,7,11,7"
|
||||
locations_default(#20156,#10000,11,7,11,7)
|
||||
hasLocation(#20155,#20156)
|
||||
#20157=*
|
||||
tokeninfo(#20157,6,#20001,31,"x6")
|
||||
hasLocation(#20157,#20069)
|
||||
#20158=*
|
||||
tokeninfo(#20158,8,#20001,32,"]")
|
||||
#20159=@"loc,{#10000},11,10,11,10"
|
||||
locations_default(#20159,#10000,11,10,11,10)
|
||||
hasLocation(#20158,#20159)
|
||||
#20160=*
|
||||
tokeninfo(#20160,8,#20001,33,".")
|
||||
#20161=@"loc,{#10000},11,11,11,11"
|
||||
locations_default(#20161,#10000,11,11,11,11)
|
||||
hasLocation(#20160,#20161)
|
||||
#20162=*
|
||||
tokeninfo(#20162,6,#20001,34,"c6")
|
||||
hasLocation(#20162,#20072)
|
||||
#20163=*
|
||||
tokeninfo(#20163,8,#20001,35,"?.")
|
||||
#20164=@"loc,{#10000},11,14,11,15"
|
||||
locations_default(#20164,#10000,11,14,11,15)
|
||||
hasLocation(#20163,#20164)
|
||||
#20165=*
|
||||
tokeninfo(#20165,8,#20001,36,"(")
|
||||
#20166=@"loc,{#10000},11,16,11,16"
|
||||
locations_default(#20166,#10000,11,16,11,16)
|
||||
hasLocation(#20165,#20166)
|
||||
#20167=*
|
||||
tokeninfo(#20167,6,#20001,37,"y6")
|
||||
hasLocation(#20167,#20074)
|
||||
#20168=*
|
||||
tokeninfo(#20168,8,#20001,38,")")
|
||||
#20169=@"loc,{#10000},11,19,11,19"
|
||||
locations_default(#20169,#10000,11,19,11,19)
|
||||
hasLocation(#20168,#20169)
|
||||
#20170=*
|
||||
tokeninfo(#20170,8,#20001,39,".")
|
||||
#20171=@"loc,{#10000},11,20,11,20"
|
||||
locations_default(#20171,#10000,11,20,11,20)
|
||||
hasLocation(#20170,#20171)
|
||||
#20172=*
|
||||
tokeninfo(#20172,6,#20001,40,"d6")
|
||||
hasLocation(#20172,#20077)
|
||||
#20173=*
|
||||
tokeninfo(#20173,8,#20001,41,";")
|
||||
#20174=@"loc,{#10000},11,23,11,23"
|
||||
locations_default(#20174,#10000,11,23,11,23)
|
||||
hasLocation(#20173,#20174)
|
||||
#20175=*
|
||||
tokeninfo(#20175,7,#20001,42,"delete")
|
||||
#20176=@"loc,{#10000},13,1,13,6"
|
||||
locations_default(#20176,#10000,13,1,13,6)
|
||||
hasLocation(#20175,#20176)
|
||||
#20177=*
|
||||
tokeninfo(#20177,6,#20001,43,"a")
|
||||
hasLocation(#20177,#20084)
|
||||
#20178=*
|
||||
tokeninfo(#20178,8,#20001,44,"?.")
|
||||
#20179=@"loc,{#10000},13,9,13,10"
|
||||
locations_default(#20179,#10000,13,9,13,10)
|
||||
hasLocation(#20178,#20179)
|
||||
#20180=*
|
||||
tokeninfo(#20180,6,#20001,45,"b")
|
||||
hasLocation(#20180,#20087)
|
||||
#20181=*
|
||||
tokeninfo(#20181,0,#20001,46,"")
|
||||
#20182=@"loc,{#10000},13,12,13,11"
|
||||
locations_default(#20182,#10000,13,12,13,11)
|
||||
hasLocation(#20181,#20182)
|
||||
#20183=*
|
||||
entry_cfg_node(#20183,#20001)
|
||||
#20184=@"loc,{#10000},1,1,1,0"
|
||||
locations_default(#20184,#10000,1,1,1,0)
|
||||
hasLocation(#20183,#20184)
|
||||
#20185=*
|
||||
exit_cfg_node(#20185,#20001)
|
||||
hasLocation(#20185,#20182)
|
||||
successor(#20078,#20083)
|
||||
successor(#20086,#20081)
|
||||
successor(#20083,#20086)
|
||||
successor(#20081,#20080)
|
||||
successor(#20083,#20080)
|
||||
successor(#20080,#20185)
|
||||
successor(#20051,#20063)
|
||||
successor(#20076,#20053)
|
||||
successor(#20073,#20055)
|
||||
successor(#20071,#20057)
|
||||
successor(#20068,#20059)
|
||||
successor(#20066,#20061)
|
||||
successor(#20063,#20066)
|
||||
successor(#20061,#20068)
|
||||
successor(#20063,#20078)
|
||||
successor(#20059,#20071)
|
||||
successor(#20057,#20073)
|
||||
successor(#20055,#20076)
|
||||
successor(#20057,#20078)
|
||||
successor(#20053,#20078)
|
||||
successor(#20040,#20042)
|
||||
successor(#20042,#20044)
|
||||
#20186=*
|
||||
guard_node(#20186,1,#20044)
|
||||
hasLocation(#20186,#20045)
|
||||
successor(#20186,#20047)
|
||||
#20187=*
|
||||
guard_node(#20187,0,#20044)
|
||||
hasLocation(#20187,#20045)
|
||||
successor(#20187,#20049)
|
||||
successor(#20044,#20186)
|
||||
successor(#20044,#20187)
|
||||
successor(#20047,#20051)
|
||||
successor(#20049,#20051)
|
||||
successor(#20033,#20037)
|
||||
successor(#20037,#20035)
|
||||
successor(#20035,#20040)
|
||||
successor(#20037,#20040)
|
||||
successor(#20022,#20028)
|
||||
successor(#20031,#20026)
|
||||
successor(#20028,#20031)
|
||||
successor(#20026,#20024)
|
||||
successor(#20028,#20033)
|
||||
successor(#20024,#20033)
|
||||
successor(#20012,#20016)
|
||||
successor(#20019,#20014)
|
||||
successor(#20016,#20019)
|
||||
successor(#20014,#20022)
|
||||
successor(#20016,#20022)
|
||||
successor(#20003,#20007)
|
||||
successor(#20010,#20005)
|
||||
successor(#20007,#20010)
|
||||
successor(#20005,#20012)
|
||||
successor(#20007,#20012)
|
||||
successor(#20183,#20003)
|
||||
numlines(#10000,13,7,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,28 @@
|
||||
#10000=@"/optional-chaining_bad1.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad1.js","optional-chaining_bad1","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: Unexpected token","new a?.();")
|
||||
#20004=@"loc,{#10000},1,8,1,8"
|
||||
locations_default(#20004,#10000,1,8,1,8)
|
||||
hasLocation(#20003,#20004)
|
||||
#20005=*
|
||||
lines(#20005,#20001,"new a?.();","")
|
||||
#20006=@"loc,{#10000},1,1,1,10"
|
||||
locations_default(#20006,#10000,1,1,1,10)
|
||||
hasLocation(#20005,#20006)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,26 @@
|
||||
#10000=@"/optional-chaining_bad2.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad2.js","optional-chaining_bad2","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: An optional chain may not be used in a tagged template expression.","a?.`{b}`;")
|
||||
hasLocation(#20003,#20002)
|
||||
#20004=*
|
||||
lines(#20004,#20001,"a?.`{b}`;","")
|
||||
#20005=@"loc,{#10000},1,1,1,9"
|
||||
locations_default(#20005,#10000,1,1,1,9)
|
||||
hasLocation(#20004,#20005)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,28 @@
|
||||
#10000=@"/optional-chaining_bad3.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad3.js","optional-chaining_bad3","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: An optional chain may not be used in a `new` expression.","new a?.b();")
|
||||
#20004=@"loc,{#10000},1,5,1,5"
|
||||
locations_default(#20004,#10000,1,5,1,5)
|
||||
hasLocation(#20003,#20004)
|
||||
#20005=*
|
||||
lines(#20005,#20001,"new a?.b();","")
|
||||
#20006=@"loc,{#10000},1,1,1,11"
|
||||
locations_default(#20006,#10000,1,1,1,11)
|
||||
hasLocation(#20005,#20006)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,26 @@
|
||||
#10000=@"/optional-chaining_bad4.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad4.js","optional-chaining_bad4","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: An optional chain may not be used in a tagged template expression.","a?.b`{c}`;")
|
||||
hasLocation(#20003,#20002)
|
||||
#20004=*
|
||||
lines(#20004,#20001,"a?.b`{c}`;","")
|
||||
#20005=@"loc,{#10000},1,1,1,10"
|
||||
locations_default(#20005,#10000,1,1,1,10)
|
||||
hasLocation(#20004,#20005)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,26 @@
|
||||
#10000=@"/optional-chaining_bad5.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad5.js","optional-chaining_bad5","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: Invalid left-hand side in assignment","a?.b = c;")
|
||||
hasLocation(#20003,#20002)
|
||||
#20004=*
|
||||
lines(#20004,#20001,"a?.b = c;","")
|
||||
#20005=@"loc,{#10000},1,1,1,9"
|
||||
locations_default(#20005,#10000,1,1,1,9)
|
||||
hasLocation(#20004,#20005)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,30 @@
|
||||
#10000=@"/optional-chaining_bad6.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad6.js","optional-chaining_bad6","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: An optional chain may not be used in a `new` expression.","new a.b?.c();
|
||||
")
|
||||
#20004=@"loc,{#10000},1,5,1,5"
|
||||
locations_default(#20004,#10000,1,5,1,5)
|
||||
hasLocation(#20003,#20004)
|
||||
#20005=*
|
||||
lines(#20005,#20001,"new a.b?.c();","
|
||||
")
|
||||
#20006=@"loc,{#10000},1,1,1,13"
|
||||
locations_default(#20006,#10000,1,1,1,13)
|
||||
hasLocation(#20005,#20006)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1077,4 +1077,8 @@ xmllocations(
|
||||
|
||||
@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property;
|
||||
|
||||
/* Last updated 2017/07/11. */
|
||||
@optionalchainable = @callexpr | @propaccess;
|
||||
|
||||
isOptionalChaining(int id: @optionalchainable ref);
|
||||
|
||||
/* Last updated 2018/10/22. */
|
||||
|
||||
@@ -1393,6 +1393,10 @@
|
||||
<k>@xmlcharacters</k>
|
||||
<v>439958</v>
|
||||
</e>
|
||||
<e>
|
||||
<k>@optionalchainable</k>
|
||||
<v>100</v>
|
||||
</e>
|
||||
</typesizes>
|
||||
<stats>
|
||||
<relation>
|
||||
@@ -19773,6 +19777,18 @@
|
||||
</columnsizes>
|
||||
<dependencies/>
|
||||
</relation>
|
||||
<relation>
|
||||
<name>isOptionalChaining</name>
|
||||
<cardinality>100</cardinality>
|
||||
<columnsizes>
|
||||
<e>
|
||||
<k>id</k>
|
||||
<v>100</v>
|
||||
</e>
|
||||
</columnsizes>
|
||||
<dependencies/>
|
||||
</relation>
|
||||
|
||||
<relation>
|
||||
<name>rangeQuantifierLowerBound</name>
|
||||
<cardinality>146</cardinality>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: 'introduce @isOptionalChaining'
|
||||
compatibility: backwards
|
||||
Reference in New Issue
Block a user