JavaScript: Move getStringValue(RegExpLiteral) into the library.

This commit is contained in:
Max Schaefer
2019-11-05 12:09:53 +00:00
parent 0edb70f373
commit a5a5debdc7
2 changed files with 26 additions and 27 deletions

View File

@@ -15,32 +15,6 @@
import javascript
/**
* Holds if `rl` is a simple constant, which is bound to the result of the predicate.
*
* For example, `/a/g` has string value `"a"` and `/abc/` has string value `"abc"`,
* while `/ab?/` and `/a(?=b)/` do not have a string value.
*
* Flags are ignored, so `/a/i` is still considered to have string value `"a"`,
* even though it also matches `"A"`.
*
* Note the somewhat subtle use of monotonic aggregate semantics, which makes the
* `strictconcat` fail if one of the children of the root is not a constant (legacy
* semantics would simply skip such children).
*/
language[monotonicAggregates]
string getStringValue(RegExpLiteral rl) {
exists(RegExpTerm root | root = rl.getRoot() |
result = root.(RegExpConstant).getValue()
or
result = strictconcat(RegExpTerm ch, int i |
ch = root.(RegExpSequence).getChild(i)
|
ch.(RegExpConstant).getValue() order by i
)
)
}
/**
* Gets a predecessor of `nd` that is not an SSA phi node.
*/
@@ -163,7 +137,7 @@ class GlobalStringReplacement extends Replacement, DataFlow::MethodCallNode {
}
override predicate replaces(string input, string output) {
input = getStringValue(pattern) and
input = pattern.getRoot().getConstantValue() and
output = this.getArgument(1).getStringValue()
or
exists(DataFlow::FunctionNode replacer, DataFlow::PropRead pr, DataFlow::ObjectLiteralNode map |

View File

@@ -173,6 +173,18 @@ class RegExpTerm extends Locatable, @regexpterm {
parent.(StringLiteral).flow() instanceof RegExpPatternSource
)
}
/**
* Gets the single string this regular-expression term matches.
*
* This predicate is only defined for (sequences/groups of) constant regular expressions.
* In particular, terms involving zero-width assertions like `^` or `\b` are not considered
* to have a constant value.
*
* Note that this predicate does not take flags of the enclosing regular-expression literal
* into account.
*/
string getConstantValue() { none() }
}
/**
@@ -223,6 +235,8 @@ class RegExpConstant extends RegExpTerm, @regexp_constant {
predicate isCharacter() { any() }
override predicate isNullable() { none() }
override string getConstantValue() { result = getValue() }
}
/**
@@ -289,6 +303,15 @@ class RegExpSequence extends RegExpTerm, @regexp_seq {
override predicate isNullable() {
forall(RegExpTerm child | child = getAChild() | child.isNullable())
}
language[monotonicAggregates]
override string getConstantValue() {
// note: due to use of monotonic aggregates, this `strictconcat` will fail if
// `getConstantValue` is undefined for any child
result = strictconcat(RegExpTerm ch, int i | ch = getChild(i) |
ch.getConstantValue() order by i
)
}
}
/**
@@ -549,6 +572,8 @@ class RegExpGroup extends RegExpTerm, @regexp_group {
string getName() { isNamedCapture(this, result) }
override predicate isNullable() { getAChild().isNullable() }
override string getConstantValue() { result = getAChild().getConstantValue() }
}
/**