mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
JS: Add Includes::Range
This commit is contained in:
@@ -183,12 +183,16 @@ module StringOps {
|
||||
*
|
||||
* Note that this also includes calls to the array method named `includes`.
|
||||
*/
|
||||
abstract class Includes extends DataFlow::Node {
|
||||
class Includes extends DataFlow::Node {
|
||||
Includes::Range range;
|
||||
|
||||
Includes() { this = range }
|
||||
|
||||
/** Gets the `A` in `A.includes(B)`. */
|
||||
abstract DataFlow::Node getBaseString();
|
||||
DataFlow::Node getBaseString() { result = range.getBaseString() }
|
||||
|
||||
/** Gets the `B` in `A.includes(B)`. */
|
||||
abstract DataFlow::Node getSubstring();
|
||||
DataFlow::Node getSubstring() { result = range.getSubstring() }
|
||||
|
||||
/**
|
||||
* Gets the polarity of the check.
|
||||
@@ -196,121 +200,144 @@ module StringOps {
|
||||
* If the polarity is `false` the check returns `true` if the string does not contain
|
||||
* the given substring.
|
||||
*/
|
||||
boolean getPolarity() { result = true }
|
||||
boolean getPolarity() { result = range.getPolarity() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a method named `includes`, assumed to refer to `String.prototype.includes`.
|
||||
*/
|
||||
private class Includes_Native extends Includes, DataFlow::MethodCallNode {
|
||||
Includes_Native() {
|
||||
getMethodName() = "includes" and
|
||||
getNumArgument() = 1
|
||||
module Includes {
|
||||
/**
|
||||
* A expression that is equivalent to `A.includes(B)` or `!A.includes(B)`.
|
||||
*
|
||||
* Note that this also includes calls to the array method named `includes`.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the `A` in `A.includes(B)`. */
|
||||
abstract DataFlow::Node getBaseString();
|
||||
|
||||
/** Gets the `B` in `A.includes(B)`. */
|
||||
abstract DataFlow::Node getSubstring();
|
||||
|
||||
/**
|
||||
* Gets the polarity of the check.
|
||||
*
|
||||
* If the polarity is `false` the check returns `true` if the string does not contain
|
||||
* the given substring.
|
||||
*/
|
||||
boolean getPolarity() { result = true }
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseString() { result = getReceiver() }
|
||||
/**
|
||||
* A call to a method named `includes`, assumed to refer to `String.prototype.includes`.
|
||||
*/
|
||||
private class Includes_Native extends Range, DataFlow::MethodCallNode {
|
||||
Includes_Native() {
|
||||
getMethodName() = "includes" and
|
||||
getNumArgument() = 1
|
||||
}
|
||||
|
||||
override DataFlow::Node getSubstring() { result = getArgument(0) }
|
||||
}
|
||||
override DataFlow::Node getBaseString() { result = getReceiver() }
|
||||
|
||||
/**
|
||||
* A call to `_.includes` or similar, assumed to operate on strings.
|
||||
*/
|
||||
private class Includes_Library extends Includes, DataFlow::CallNode {
|
||||
Includes_Library() {
|
||||
exists(string name |
|
||||
this = LodashUnderscore::member(name).getACall() and
|
||||
(name = "includes" or name = "include" or name = "contains")
|
||||
)
|
||||
override DataFlow::Node getSubstring() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseString() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getSubstring() { result = getArgument(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A check of form `A.indexOf(B) !== -1` or similar.
|
||||
*/
|
||||
private class Includes_IndexOfEquals extends Includes, DataFlow::ValueNode {
|
||||
MethodCallExpr indexOf;
|
||||
|
||||
override EqualityTest astNode;
|
||||
|
||||
Includes_IndexOfEquals() {
|
||||
exists(Expr index | astNode.hasOperands(indexOf, index) |
|
||||
// one operand is of the form `whitelist.indexOf(x)`
|
||||
indexOf.getMethodName() = "indexOf" and
|
||||
// and the other one is -1
|
||||
index.getIntValue() = -1
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() }
|
||||
|
||||
override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() }
|
||||
|
||||
override boolean getPolarity() { result = astNode.getPolarity().booleanNot() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A check of form `A.indexOf(B) >= 0` or similar.
|
||||
*/
|
||||
private class Includes_IndexOfRelational extends Includes, DataFlow::ValueNode {
|
||||
MethodCallExpr indexOf;
|
||||
|
||||
override RelationalComparison astNode;
|
||||
|
||||
boolean polarity;
|
||||
|
||||
Includes_IndexOfRelational() {
|
||||
exists(Expr lesser, Expr greater |
|
||||
astNode.getLesserOperand() = lesser and
|
||||
astNode.getGreaterOperand() = greater and
|
||||
indexOf.getMethodName() = "indexOf" and
|
||||
indexOf.getNumArgument() = 1
|
||||
|
|
||||
polarity = true and
|
||||
greater = indexOf and
|
||||
(
|
||||
lesser.getIntValue() = 0 and astNode.isInclusive()
|
||||
or
|
||||
lesser.getIntValue() = -1 and not astNode.isInclusive()
|
||||
/**
|
||||
* A call to `_.includes` or similar, assumed to operate on strings.
|
||||
*/
|
||||
private class Includes_Library extends Range, DataFlow::CallNode {
|
||||
Includes_Library() {
|
||||
exists(string name |
|
||||
this = LodashUnderscore::member(name).getACall() and
|
||||
(name = "includes" or name = "include" or name = "contains")
|
||||
)
|
||||
or
|
||||
polarity = false and
|
||||
lesser = indexOf and
|
||||
(
|
||||
greater.getIntValue() = -1 and astNode.isInclusive()
|
||||
or
|
||||
greater.getIntValue() = 0 and not astNode.isInclusive()
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseString() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getSubstring() { result = getArgument(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A check of form `A.indexOf(B) !== -1` or similar.
|
||||
*/
|
||||
private class Includes_IndexOfEquals extends Range, DataFlow::ValueNode {
|
||||
MethodCallExpr indexOf;
|
||||
|
||||
override EqualityTest astNode;
|
||||
|
||||
Includes_IndexOfEquals() {
|
||||
exists(Expr index | astNode.hasOperands(indexOf, index) |
|
||||
// one operand is of the form `whitelist.indexOf(x)`
|
||||
indexOf.getMethodName() = "indexOf" and
|
||||
// and the other one is -1
|
||||
index.getIntValue() = -1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() }
|
||||
|
||||
override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() }
|
||||
|
||||
override boolean getPolarity() { result = astNode.getPolarity().booleanNot() }
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() }
|
||||
/**
|
||||
* A check of form `A.indexOf(B) >= 0` or similar.
|
||||
*/
|
||||
private class Includes_IndexOfRelational extends Range, DataFlow::ValueNode {
|
||||
MethodCallExpr indexOf;
|
||||
|
||||
override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() }
|
||||
override RelationalComparison astNode;
|
||||
|
||||
override boolean getPolarity() { result = polarity }
|
||||
}
|
||||
boolean polarity;
|
||||
|
||||
/**
|
||||
* An expression of form `~A.indexOf(B)` which, when coerced to a boolean, is equivalent to `A.includes(B)`.
|
||||
*/
|
||||
private class Includes_IndexOfBitwise extends Includes, DataFlow::ValueNode {
|
||||
MethodCallExpr indexOf;
|
||||
Includes_IndexOfRelational() {
|
||||
exists(Expr lesser, Expr greater |
|
||||
astNode.getLesserOperand() = lesser and
|
||||
astNode.getGreaterOperand() = greater and
|
||||
indexOf.getMethodName() = "indexOf" and
|
||||
indexOf.getNumArgument() = 1
|
||||
|
|
||||
polarity = true and
|
||||
greater = indexOf and
|
||||
(
|
||||
lesser.getIntValue() = 0 and astNode.isInclusive()
|
||||
or
|
||||
lesser.getIntValue() = -1 and not astNode.isInclusive()
|
||||
)
|
||||
or
|
||||
polarity = false and
|
||||
lesser = indexOf and
|
||||
(
|
||||
greater.getIntValue() = -1 and astNode.isInclusive()
|
||||
or
|
||||
greater.getIntValue() = 0 and not astNode.isInclusive()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override BitNotExpr astNode;
|
||||
override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() }
|
||||
|
||||
Includes_IndexOfBitwise() {
|
||||
astNode.getOperand() = indexOf and
|
||||
indexOf.getMethodName() = "indexOf"
|
||||
override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() }
|
||||
|
||||
override boolean getPolarity() { result = polarity }
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() }
|
||||
/**
|
||||
* An expression of form `~A.indexOf(B)` which, when coerced to a boolean, is equivalent to `A.includes(B)`.
|
||||
*/
|
||||
private class Includes_IndexOfBitwise extends Range, DataFlow::ValueNode {
|
||||
MethodCallExpr indexOf;
|
||||
|
||||
override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() }
|
||||
override BitNotExpr astNode;
|
||||
|
||||
Includes_IndexOfBitwise() {
|
||||
astNode.getOperand() = indexOf and
|
||||
indexOf.getMethodName() = "indexOf"
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() }
|
||||
|
||||
override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user