JavaScript: Autoformat all QL files.

This commit is contained in:
Max Schaefer
2019-01-07 10:15:45 +00:00
parent aa6b89dc34
commit 31bb39a810
380 changed files with 9957 additions and 13923 deletions

View File

@@ -21,16 +21,19 @@ predicate nonLocalIterator(EnhancedForLoop f, string descr) {
f.getIterator() instanceof PropAccess and descr = "a property"
or
// iterator is not a purely local variable:
exists (Variable v | v = f.getAnIterationVariable() |
exists(Variable v | v = f.getAnIterationVariable() |
// either it is global...
v.isGlobal() and descr = "a global variable" or
v.isGlobal() and descr = "a global variable"
or
// ...or it is captured by an inner function
v.isLocal() and v.isCaptured() and descr = "captured"
)
}
from EnhancedForLoop f, string reason
where nonLocalIterator(f, reason) and
// exclude toplevel statements, since the toplevel is unlikely to be optimized anyway
not f.getContainer() instanceof TopLevel
select f.getIterator(), "This loop may prevent optimization because its iteration variable is " + reason + "."
where
nonLocalIterator(f, reason) and
// exclude toplevel statements, since the toplevel is unlikely to be optimized anyway
not f.getContainer() instanceof TopLevel
select f.getIterator(),
"This loop may prevent optimization because its iteration variable is " + reason + "."

View File

@@ -83,14 +83,17 @@ import javascript
* A branch in a disjunction that is the root node in a literal, or a literal
* whose root node is not a disjunction.
*/
class RegExpRoot extends @regexpterm { // RegExpTerm is abstract, so do not extend it.
class RegExpRoot extends @regexpterm {
// RegExpTerm is abstract, so do not extend it.
RegExpRoot() {
exists (RegExpLiteral literal, RegExpAlt alt | alt.getParent() = literal |
this = alt.getAChild())
exists(RegExpLiteral literal, RegExpAlt alt | alt.getParent() = literal |
this = alt.getAChild()
)
or
exists (RegExpLiteral literal |
not exists (RegExpAlt alt | alt.getParent() = literal) and
this.(RegExpTerm).getParent() = literal)
exists(RegExpLiteral literal |
not exists(RegExpAlt alt | alt.getParent() = literal) and
this.(RegExpTerm).getParent() = literal
)
}
/**
@@ -98,10 +101,9 @@ class RegExpRoot extends @regexpterm { // RegExpTerm is abstract, so do not exte
*/
predicate isRelevant() {
// there is at least one repetition
exists (RegExpRepetition rep | getRoot(rep) = this)
and
exists(RegExpRepetition rep | getRoot(rep) = this) and
// there are no lookbehinds
not exists (RegExpLookbehind lbh | getRoot(lbh) = this)
not exists(RegExpLookbehind lbh | getRoot(lbh) = this)
}
string toString() { result = this.(RegExpTerm).toString() }
@@ -132,8 +134,7 @@ RegExpRoot getRoot(RegExpTerm term) {
*/
newtype TInputSymbol =
/** An input symbol corresponding to character `c`. */
Char(string c) { c = any(RegExpConstant cc).getValue() }
or
Char(string c) { c = any(RegExpConstant cc).getValue() } or
/**
* An input symbol representing all characters matched by
* (positive, non-universal) character class `recc`.
@@ -142,18 +143,14 @@ newtype TInputSymbol =
getRoot(recc).isRelevant() and
not recc.isInverted() and
not isUniversalClass(recc)
}
or
} or
/** An input symbol representing all characters matched by `.`. */
Dot()
or
Dot() or
/** An input symbol representing all characters. */
Any()
or
Any() or
/** An epsilon transition in the automaton. */
Epsilon()
/**
* Holds if character class `cc` matches all characters.
*/
@@ -163,9 +160,10 @@ predicate isUniversalClass(RegExpCharacterClass cc) {
or
// [\w\W] and similar
not cc.isInverted() and
exists (string cce1, string cce2 |
exists(string cce1, string cce2 |
cce1 = cc.getAChild().(RegExpCharacterClassEscape).getValue() and
cce2 = cc.getAChild().(RegExpCharacterClassEscape).getValue() |
cce2 = cc.getAChild().(RegExpCharacterClassEscape).getValue()
|
cce1 != cce2 and cce1.toLowerCase() = cce2.toLowerCase()
)
}
@@ -174,14 +172,15 @@ predicate isUniversalClass(RegExpCharacterClass cc) {
* An abstract input symbol, representing a set of concrete characters.
*/
class InputSymbol extends TInputSymbol {
InputSymbol() {
not this instanceof Epsilon
}
InputSymbol() { not this instanceof Epsilon }
string toString() {
this = Char(result) or
result = any(RegExpCharacterClass recc | this = CharClass(recc)).toString() or
this = Dot() and result = "." or
this = Char(result)
or
result = any(RegExpCharacterClass recc | this = CharClass(recc)).toString()
or
this = Dot() and result = "."
or
this = Any() and result = "[^]"
}
}
@@ -192,20 +191,26 @@ class InputSymbol extends TInputSymbol {
string getCCLowerBound(RegExpTerm t) {
t.getParent() instanceof RegExpCharacterClass and
(
result = t.(RegExpConstant).getValue() or
t.(RegExpCharacterRange).isRange(result, _) or
exists (string name | name = t.(RegExpCharacterClassEscape).getValue() |
name = "w" and result = "0" or
name = "W" and result = "" or
name = "s" and result = "" or
name = "S" and result = "")
result = t.(RegExpConstant).getValue()
or
t.(RegExpCharacterRange).isRange(result, _)
or
exists(string name | name = t.(RegExpCharacterClassEscape).getValue() |
name = "w" and result = "0"
or
name = "W" and result = ""
or
name = "s" and result = ""
or
name = "S" and result = ""
)
)
}
/**
* The highest character used in a regular expression. Used to represent intervals without an upper bound.
*/
string highestCharacter() { result = max(RegExpConstant c || c.getValue()) }
string highestCharacter() { result = max(RegExpConstant c | | c.getValue()) }
/**
* Gets an upper bound on the characters matched by the given character class term.
@@ -213,13 +218,19 @@ string highestCharacter() { result = max(RegExpConstant c || c.getValue()) }
string getCCUpperBound(RegExpTerm t) {
t.getParent() instanceof RegExpCharacterClass and
(
result = t.(RegExpConstant).getValue() or
t.(RegExpCharacterRange).isRange(_, result) or
exists (string name | name = t.(RegExpCharacterClassEscape).getValue() |
name = "w" and result = "z" or
name = "W" and result = highestCharacter() or
name = "s" and result = highestCharacter() or
name = "S" and result = highestCharacter())
result = t.(RegExpConstant).getValue()
or
t.(RegExpCharacterRange).isRange(_, result)
or
exists(string name | name = t.(RegExpCharacterClassEscape).getValue() |
name = "w" and result = "z"
or
name = "W" and result = highestCharacter()
or
name = "s" and result = highestCharacter()
or
name = "S" and result = highestCharacter()
)
)
}
@@ -228,10 +239,11 @@ string getCCUpperBound(RegExpTerm t) {
* in the interval `lo-hi`.
*/
predicate hasBounds(RegExpRoot l, InputSymbol s, string lo, string hi) {
exists (RegExpCharacterClass cc | s = CharClass(cc) |
exists(RegExpCharacterClass cc | s = CharClass(cc) |
l = getRoot(cc) and
lo = min(getCCLowerBound(cc.getAChild())) and
hi = max(getCCUpperBound(cc.getAChild())))
hi = max(getCCUpperBound(cc.getAChild()))
)
}
/**
@@ -240,21 +252,18 @@ predicate hasBounds(RegExpRoot l, InputSymbol s, string lo, string hi) {
* This predicate is over-approximate; it is only used for pruning the search space.
*/
predicate compatible(InputSymbol s1, InputSymbol s2) {
exists (RegExpRoot l, string lo1, string lo2, string hi1, string hi2 |
hasBounds(l, s1, lo1, hi1) and hasBounds(l, s2, lo2, hi2) and
max(string s | s = lo1 or s = lo2) <= min(string s | s = hi1 or s = hi2))
exists(RegExpRoot l, string lo1, string lo2, string hi1, string hi2 |
hasBounds(l, s1, lo1, hi1) and
hasBounds(l, s2, lo2, hi2) and
max(string s | s = lo1 or s = lo2) <= min(string s | s = hi1 or s = hi2)
)
or
exists (intersect(s1, s2))
exists(intersect(s1, s2))
}
newtype TState =
Match(RegExpTerm t) {
getRoot(t).isRelevant()
}
or
Accept(RegExpRoot l) {
l.isRelevant()
}
Match(RegExpTerm t) { getRoot(t).isRelevant() } or
Accept(RegExpRoot l) { l.isRelevant() }
/**
* A state in the NFA corresponding to a regular expression.
@@ -267,24 +276,21 @@ newtype TState =
class State extends TState {
RegExpParent repr;
State() {
this = Match(repr) or this = Accept(repr)
}
State() { this = Match(repr) or this = Accept(repr) }
string toString() {
result = "Match(" + (RegExpTerm)repr + ")" or
result = "Accept(" + (RegExpRoot)repr + ")"
result = "Match(" + repr.(RegExpTerm) + ")" or
result = "Accept(" + repr.(RegExpRoot) + ")"
}
Location getLocation() {
result = repr.getLocation()
}
Location getLocation() { result = repr.getLocation() }
}
class EdgeLabel extends TInputSymbol {
string toString() {
this = Epsilon() and result = "" or
exists (InputSymbol s | this = s and result = s.toString())
this = Epsilon() and result = ""
or
exists(InputSymbol s | this = s and result = s.toString())
}
}
@@ -292,78 +298,63 @@ class EdgeLabel extends TInputSymbol {
* Gets a state the NFA may be in after matching `t`.
*/
State after(RegExpTerm t) {
exists (RegExpAlt alt | t = alt.getAChild() |
result = after(alt)
exists(RegExpAlt alt | t = alt.getAChild() | result = after(alt))
or
exists(RegExpSequence seq, int i | t = seq.getChild(i) |
result = Match(seq.getChild(i + 1))
or
i + 1 = seq.getNumChild() and result = after(seq)
)
or
exists (RegExpSequence seq, int i | t = seq.getChild(i) |
result = Match(seq.getChild(i+1)) or
i+1 = seq.getNumChild() and result = after(seq)
)
exists(RegExpGroup grp | t = grp.getAChild() | result = after(grp))
or
exists (RegExpGroup grp | t = grp.getAChild() |
result = after(grp)
)
exists(RegExpStar star | t = star.getAChild() | result = Match(star))
or
exists (RegExpStar star | t = star.getAChild() |
result = Match(star)
)
or
exists (RegExpPlus plus | t = plus.getAChild() |
exists(RegExpPlus plus | t = plus.getAChild() |
result = Match(plus) or
result = after(plus)
)
or
exists (RegExpOpt opt | t = opt.getAChild() |
result = after(opt)
)
exists(RegExpOpt opt | t = opt.getAChild() | result = after(opt))
or
exists (RegExpRoot root | t = root |
result = Accept(root)
)
exists(RegExpRoot root | t = root | result = Accept(root))
}
/**
* Holds if the NFA has a transition from `q1` to `q2` labelled with `lbl`.
*/
predicate delta(State q1, EdgeLabel lbl, State q2) {
exists (RegExpConstant s |
q1 = Match(s) and lbl = Char(s.getValue()) and q2 = after(s)
)
exists(RegExpConstant s | q1 = Match(s) and lbl = Char(s.getValue()) and q2 = after(s))
or
exists (RegExpDot dot, RegExpLiteral rel |
q1 = Match(dot) and q2 = after(dot) and rel = dot.getLiteral() |
exists(RegExpDot dot, RegExpLiteral rel |
q1 = Match(dot) and q2 = after(dot) and rel = dot.getLiteral()
|
if rel.isDotAll() then lbl = Any() else lbl = Dot()
)
or
exists (RegExpCharacterClass cc |
isUniversalClass(cc) and q1 = Match(cc) and lbl = Any() and q2 = after(cc) or
exists(RegExpCharacterClass cc |
isUniversalClass(cc) and q1 = Match(cc) and lbl = Any() and q2 = after(cc)
or
q1 = Match(cc) and lbl = CharClass(cc) and q2 = after(cc)
)
or
exists (RegExpAlt alt | lbl = Epsilon() |
q1 = Match(alt) and q2 = Match(alt.getAChild())
)
exists(RegExpAlt alt | lbl = Epsilon() | q1 = Match(alt) and q2 = Match(alt.getAChild()))
or
exists (RegExpSequence seq | lbl = Epsilon() |
q1 = Match(seq) and q2 = Match(seq.getChild(0))
)
exists(RegExpSequence seq | lbl = Epsilon() | q1 = Match(seq) and q2 = Match(seq.getChild(0)))
or
exists (RegExpGroup grp | lbl = Epsilon() |
q1 = Match(grp) and q2 = Match(grp.getChild(0))
)
exists(RegExpGroup grp | lbl = Epsilon() | q1 = Match(grp) and q2 = Match(grp.getChild(0)))
or
exists (RegExpStar star | lbl = Epsilon() |
q1 = Match(star) and q2 = Match(star.getChild(0)) or
exists(RegExpStar star | lbl = Epsilon() |
q1 = Match(star) and q2 = Match(star.getChild(0))
or
q1 = Match(star) and q2 = after(star)
)
or
exists (RegExpPlus plus | lbl = Epsilon() |
q1 = Match(plus) and q2 = Match(plus.getChild(0))
)
exists(RegExpPlus plus | lbl = Epsilon() | q1 = Match(plus) and q2 = Match(plus.getChild(0)))
or
exists (RegExpOpt opt | lbl = Epsilon() |
q1 = Match(opt) and q2 = Match(opt.getChild(0)) or
exists(RegExpOpt opt | lbl = Epsilon() |
q1 = Match(opt) and q2 = Match(opt.getChild(0))
or
q1 = Match(opt) and q2 = after(opt)
)
}
@@ -371,26 +362,19 @@ predicate delta(State q1, EdgeLabel lbl, State q2) {
/**
* Gets a state that `q` has an epsilon transition to.
*/
State epsilonSucc(State q) {
delta(q, Epsilon(), result)
}
State epsilonSucc(State q) { delta(q, Epsilon(), result) }
/**
* Gets a state that has an epsilon transition to `q`.
*/
State epsilonPred(State q) {
q = epsilonSucc(result)
}
State epsilonPred(State q) { q = epsilonSucc(result) }
/**
* Holds if there is a state `q` that can be reached from `q1`
* along epsilon edges, such that there is a transition from
* `q` to `q2` that consumes symbol `s`.
*/
predicate deltaClosed(State q1, InputSymbol s, State q2) {
delta(epsilonSucc*(q1), s, q2)
}
predicate deltaClosed(State q1, InputSymbol s, State q2) { delta(epsilonSucc*(q1), s, q2) }
/**
* A state in the product automaton.
@@ -411,6 +395,7 @@ newtype TStatePair =
class StatePair extends TStatePair {
State q1;
State q2;
StatePair() { this = MkStatePair(q1, q2) }
@@ -448,15 +433,20 @@ int statePairDist(StatePair q, StatePair r) =
*/
pragma[noopt]
predicate isFork(State q, InputSymbol s1, InputSymbol s2, State r1, State r2) {
exists (State q1, State q2 |
q1 = epsilonSucc*(q) and delta(q1, s1, r1) and
q2 = epsilonSucc*(q) and delta(q2, s2, r2) and
exists(State q1, State q2 |
q1 = epsilonSucc*(q) and
delta(q1, s1, r1) and
q2 = epsilonSucc*(q) and
delta(q2, s2, r2) and
// Use pragma[noopt] to prevent compatible(s1,s2) from being the starting point of the join.
// From (s1,s2) it would find a huge number of intermediate state pairs (q1,q2) originating from different literals,
// and discover at the end that no `q` can reach both `q1` and `q2` by epsilon transitions.
compatible(s1, s2) |
s1 != s2 or
r1 != r2 or
compatible(s1, s2)
|
s1 != s2
or
r1 != r2
or
r1 = r2 and q1 != q2
)
}
@@ -466,9 +456,7 @@ predicate isFork(State q, InputSymbol s1, InputSymbol s2, State r1, State r2) {
* components of `r` labelled with `s1` and `s2`, respectively.
*/
predicate step(StatePair q, InputSymbol s1, InputSymbol s2, StatePair r) {
exists (State r1, State r2 |
step(q, s1, s2, r1, r2) and r = mkStatePair(r1, r2)
)
exists(State r1, State r2 | step(q, s1, s2, r1, r2) and r = mkStatePair(r1, r2))
}
/**
@@ -476,8 +464,9 @@ predicate step(StatePair q, InputSymbol s1, InputSymbol s2, StatePair r) {
* labelled with `s1` and `s2`, respectively.
*/
predicate step(StatePair q, InputSymbol s1, InputSymbol s2, State r1, State r2) {
exists (State q1, State q2 | q = MkStatePair(q1, q2) |
deltaClosed(q1, s1, r1) and deltaClosed(q2, s2, r2) and
exists(State q1, State q2 | q = MkStatePair(q1, q2) |
deltaClosed(q1, s1, r1) and
deltaClosed(q2, s2, r2) and
compatible(s1, s2)
)
}
@@ -489,10 +478,11 @@ predicate step(StatePair q, InputSymbol s1, InputSymbol s2, State r1, State r2)
newtype Trace =
Nil() or
Step(InputSymbol s1, InputSymbol s2, Trace t) {
exists (StatePair p |
exists(StatePair p |
isReachableFromFork(_, p, t, _) and
step(p, s1, s2, _)
) or
)
or
t = Nil() and isFork(_, s1, s2, _, _)
}
@@ -500,28 +490,42 @@ newtype Trace =
* Gets a character that is represented by both `c` and `d`.
*/
string intersect(InputSymbol c, InputSymbol d) {
c = Char(result) and (
d = Char(result) or
exists (RegExpCharacterClass cc | d = CharClass(cc) |
exists (RegExpTerm child | child = cc.getAChild() |
result = child.(RegExpConstant).getValue() or
exists (string lo, string hi | child.(RegExpCharacterRange).isRange(lo, hi) |
c = Char(result) and
(
d = Char(result)
or
exists(RegExpCharacterClass cc | d = CharClass(cc) |
exists(RegExpTerm child | child = cc.getAChild() |
result = child.(RegExpConstant).getValue()
or
exists(string lo, string hi | child.(RegExpCharacterRange).isRange(lo, hi) |
lo <= result and result <= hi
)
)
) or
d = Dot() and not (result = "\n" or result = "\r") or
)
or
d = Dot() and
not (result = "\n" or result = "\r")
or
d = Any()
) or
exists (RegExpCharacterClass cc | c = CharClass(cc) and result = choose(cc) |
d = CharClass(cc) or
d = Dot() and not (result = "\n" or result = "\r") or
)
or
exists(RegExpCharacterClass cc | c = CharClass(cc) and result = choose(cc) |
d = CharClass(cc)
or
d = Dot() and
not (result = "\n" or result = "\r")
or
d = Any()
) or
c = Dot() and (
d = Dot() and result = "a" or
)
or
c = Dot() and
(
d = Dot() and result = "a"
or
d = Any() and result = "a"
) or
)
or
c = Any() and d = Any() and result = "a"
or
result = intersect(d, c)
@@ -532,11 +536,11 @@ string intersect(InputSymbol c, InputSymbol d) {
*/
string choose(RegExpCharacterClass cc) {
result = min(string c |
exists (RegExpTerm child | child = cc.getAChild() |
c = child.(RegExpConstant).getValue() or
child.(RegExpCharacterRange).isRange(c, _)
exists(RegExpTerm child | child = cc.getAChild() |
c = child.(RegExpConstant).getValue() or
child.(RegExpCharacterRange).isRange(c, _)
)
)
)
}
/**
@@ -545,7 +549,7 @@ string choose(RegExpCharacterClass cc) {
string concretise(Trace t) {
t = Nil() and result = ""
or
exists (InputSymbol s1, InputSymbol s2, Trace rest | t = Step(s1, s2, rest) |
exists(InputSymbol s1, InputSymbol s2, Trace rest | t = Step(s1, s2, rest) |
result = concretise(rest) + intersect(s1, s2)
)
}
@@ -555,15 +559,15 @@ string concretise(Trace t) {
* a path from `r` back to `(fork, fork)` with `rem` steps.
*/
predicate isReachableFromFork(State fork, StatePair r, Trace w, int rem) {
exists (InputSymbol s1, InputSymbol s2, State q1, State q2 |
exists(InputSymbol s1, InputSymbol s2, State q1, State q2 |
isFork(fork, s1, s2, q1, q2) and
r = MkStatePair(q1, q2) and
w = Step(s1, s2, Nil()) and
rem = statePairDist(r, MkStatePair(fork, fork))
)
or
exists (StatePair p, Trace v, InputSymbol s1, InputSymbol s2 |
isReachableFromFork(fork, p, v, rem+1) and
exists(StatePair p, Trace v, InputSymbol s1, InputSymbol s2 |
isReachableFromFork(fork, p, v, rem + 1) and
step(p, s1, s2, r) and
w = Step(s1, s2, v) and
rem > 0
@@ -583,12 +587,12 @@ StatePair getAForkPair(State fork) {
* Holds if `fork` is a pumpable fork with word `w`.
*/
predicate isPumpable(State fork, string w) {
exists (StatePair q, Trace t |
exists(StatePair q, Trace t |
isReachableFromFork(fork, q, t, _) and
(
q = getAForkPair(fork) and w = concretise(t)
or
exists (InputSymbol s1, InputSymbol s2 |
exists(InputSymbol s1, InputSymbol s2 |
step(q, s1, s2, getAForkPair(fork)) and
w = concretise(Step(s1, s2, t))
)
@@ -608,8 +612,12 @@ predicate isPumpable(State fork, string w) {
*/
State process(State fork, string w, int i) {
isPumpable(fork, w) and
exists (State prev | i = 0 and prev = fork or prev = process(fork, w, i-1) |
exists (InputSymbol s |
exists(State prev |
i = 0 and prev = fork
or
prev = process(fork, w, i - 1)
|
exists(InputSymbol s |
deltaClosed(prev, s, result) and
exists(intersect(Char(w.charAt(i)), s))
)
@@ -626,7 +634,10 @@ string escape(string s) {
}
from RegExpTerm t, string c
where c = min(string w | isPumpable(Match(t), w)) and not isPumpable(epsilonSucc+(Match(t)), _) and
not epsilonSucc*(process(Match(t), c, c.length()-1)) = Accept(_)
select t, "This part of the regular expression may cause exponential backtracking on strings " +
"containing many repetitions of '" + escape(c) + "'."
where
c = min(string w | isPumpable(Match(t), w)) and
not isPumpable(epsilonSucc+(Match(t)), _) and
not epsilonSucc*(process(Match(t), c, c.length() - 1)) = Accept(_)
select t,
"This part of the regular expression may cause exponential backtracking on strings " +
"containing many repetitions of '" + escape(c) + "'."

View File

@@ -13,10 +13,12 @@
import javascript
from Function f, SimpleParameter p, VarAccess assgn
where p = f.getAParameter() and
f.usesArgumentsObject() and
assgn = p.getVariable().getAnAccess() and
assgn.isLValue()
select p, "This parameter is reassigned $@, " +
"which may prevent optimization because the surrounding function " +
"uses the arguments object.", assgn, "here"
where
p = f.getAParameter() and
f.usesArgumentsObject() and
assgn = p.getVariable().getAnAccess() and
assgn.isLValue()
select p,
"This parameter is reassigned $@, " +
"which may prevent optimization because the surrounding function " +
"uses the arguments object.", assgn, "here"