mirror of
https://github.com/github/codeql.git
synced 2026-05-02 20:25:13 +02:00
JavaScript: Autoformat all QL files.
This commit is contained in:
@@ -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 + "."
|
||||
|
||||
@@ -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) + "'."
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user