Merge pull request #8149 from asgerf/shared/use-shared-access-path-syntax

Shared: use shared access path syntax to parse arguments in CSV rows
This commit is contained in:
Asger F
2022-02-25 14:04:18 +01:00
committed by GitHub
9 changed files with 422 additions and 144 deletions

View File

@@ -6,6 +6,15 @@
* (which does not use the shared data flow libraries).
*/
/**
* Convenience-predicate for extracting two capture groups at once.
*/
bindingset[input, regexp]
private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) {
capture1 = input.regexpCapture(regexp, 1) and
capture2 = input.regexpCapture(regexp, 2)
}
/** Companion module to the `AccessPath` class. */
module AccessPath {
/** A string that should be parsed as an access path. */
@@ -13,6 +22,95 @@ module AccessPath {
bindingset[this]
Range() { any() }
}
/**
* Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
* of the constant or any value contained in the interval.
*/
bindingset[arg]
int parseInt(string arg) {
result = arg.toInt()
or
// Match "n1..n2"
exists(string lo, string hi |
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.(-?\\d+)", lo, hi) and
result = [lo.toInt() .. hi.toInt()]
)
}
/**
* Parses a lower-bounded interval `n..` and gets the lower bound.
*/
bindingset[arg]
private int parseLowerBound(string arg) {
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
}
/**
* Parses an integer constant or interval (bounded or unbounded) that explicitly
* references the arity, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
private int parseIntWithExplicitArity(string arg, int arity) {
result >= 0 and // do not allow N-1 to resolve to a negative index
exists(string lo |
// N-x
lo = arg.regexpCapture("N-(\\d+)", 1) and
result = arity - lo.toInt()
or
// N-x..
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
result = [arity - lo.toInt(), arity - 1]
)
or
exists(string lo, string hi |
// x..N-y
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [lo.toInt() .. arity - hi.toInt()]
or
// N-x..N-y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. arity - hi.toInt()] and
result >= 0
or
// N-x..y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. hi.toInt()] and
result >= 0
)
}
/**
* Parses an integer constant or interval (bounded or unbounded) and gets any
* of the integers contained within (of which there may be infinitely many).
*
* Has no result for arguments involving an explicit arity, such as `N-1`.
*/
bindingset[arg, result]
int parseIntUnbounded(string arg) {
result = parseInt(arg)
or
result >= parseLowerBound(arg)
}
/**
* Parses an integer constant or interval (bounded or unbounded) that
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
int parseIntWithArity(string arg, int arity) {
result = parseInt(arg)
or
result in [parseLowerBound(arg) .. arity - 1]
or
result = parseIntWithExplicitArity(arg, arity)
}
}
/** Gets the `n`th token on the access path as a string. */

View File

@@ -124,21 +124,26 @@ predicate sinkElement(Element e, string input, string kind) {
/** Gets the summary component for specification component `c`, if any. */
bindingset[c]
SummaryComponent interpretComponentSpecific(string c) {
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
c = "Element" and result = SummaryComponent::content(any(ElementContent ec))
or
// Qualified names may contain commas,such as in `Tuple<,>`, so get the entire argument list
// rather than an individual argument.
exists(Field f |
c.regexpCapture("Field\\[(.+)\\]", 1) = f.getQualifiedName() and
c.getName() = "Field" and
c.getArgumentList() = f.getQualifiedName() and
result = SummaryComponent::content(any(FieldContent fc | fc.getField() = f))
)
or
exists(Property p |
c.regexpCapture("Property\\[(.+)\\]", 1) = p.getQualifiedName() and
c.getName() = "Property" and
c.getArgumentList() = p.getQualifiedName() and
result = SummaryComponent::content(any(PropertyContent pc | pc.getProperty() = p))
)
or
exists(SyntheticField f |
c.regexpCapture("SyntheticField\\[(.+)\\]", 1) = f and
c.getName() = "SyntheticField" and
c.getArgumentList() = f and
result = SummaryComponent::content(any(SyntheticFieldContent sfc | sfc.getField() = f))
)
}
@@ -253,21 +258,10 @@ predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode n) {
)
}
bindingset[s]
private int parseIntegerPosition(string s) {
result = s.regexpCapture("([0-9]+)", 1).toInt()
or
exists(int n1, int n2 |
s.regexpCapture("([0-9]+)\\.\\.([0-9]+)", 1).toInt() = n1 and
s.regexpCapture("([0-9]+)\\.\\.([0-9]+)", 2).toInt() = n2 and
result in [n1 .. n2]
)
}
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
bindingset[s]
ArgumentPosition parseParamBody(string s) {
result.getPosition() = parseIntegerPosition(s)
result.getPosition() = AccessPath::parseInt(s)
or
s = "This" and
result.isQualifier()
@@ -276,7 +270,7 @@ ArgumentPosition parseParamBody(string s) {
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
bindingset[s]
ParameterPosition parseArgBody(string s) {
result.getPosition() = parseIntegerPosition(s)
result.getPosition() = AccessPath::parseInt(s)
or
s = "Qualifier" and
result.isThisParameter()

View File

@@ -6,6 +6,15 @@
* (which does not use the shared data flow libraries).
*/
/**
* Convenience-predicate for extracting two capture groups at once.
*/
bindingset[input, regexp]
private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) {
capture1 = input.regexpCapture(regexp, 1) and
capture2 = input.regexpCapture(regexp, 2)
}
/** Companion module to the `AccessPath` class. */
module AccessPath {
/** A string that should be parsed as an access path. */
@@ -13,6 +22,95 @@ module AccessPath {
bindingset[this]
Range() { any() }
}
/**
* Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
* of the constant or any value contained in the interval.
*/
bindingset[arg]
int parseInt(string arg) {
result = arg.toInt()
or
// Match "n1..n2"
exists(string lo, string hi |
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.(-?\\d+)", lo, hi) and
result = [lo.toInt() .. hi.toInt()]
)
}
/**
* Parses a lower-bounded interval `n..` and gets the lower bound.
*/
bindingset[arg]
private int parseLowerBound(string arg) {
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
}
/**
* Parses an integer constant or interval (bounded or unbounded) that explicitly
* references the arity, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
private int parseIntWithExplicitArity(string arg, int arity) {
result >= 0 and // do not allow N-1 to resolve to a negative index
exists(string lo |
// N-x
lo = arg.regexpCapture("N-(\\d+)", 1) and
result = arity - lo.toInt()
or
// N-x..
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
result = [arity - lo.toInt(), arity - 1]
)
or
exists(string lo, string hi |
// x..N-y
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [lo.toInt() .. arity - hi.toInt()]
or
// N-x..N-y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. arity - hi.toInt()] and
result >= 0
or
// N-x..y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. hi.toInt()] and
result >= 0
)
}
/**
* Parses an integer constant or interval (bounded or unbounded) and gets any
* of the integers contained within (of which there may be infinitely many).
*
* Has no result for arguments involving an explicit arity, such as `N-1`.
*/
bindingset[arg, result]
int parseIntUnbounded(string arg) {
result = parseInt(arg)
or
result >= parseLowerBound(arg)
}
/**
* Parses an integer constant or interval (bounded or unbounded) that
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
int parseIntWithArity(string arg, int arity) {
result = parseInt(arg)
or
result in [parseLowerBound(arg) .. arity - 1]
or
result = parseIntWithExplicitArity(arg, arity)
}
}
/** Gets the `n`th token on the access path as a string. */

View File

@@ -200,21 +200,10 @@ predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode n) {
)
}
bindingset[s]
private int parsePosition(string s) {
result = s.regexpCapture("([-0-9]+)", 1).toInt()
or
exists(int n1, int n2 |
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 1).toInt() = n1 and
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 2).toInt() = n2 and
result in [n1 .. n2]
)
}
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
bindingset[s]
ArgumentPosition parseParamBody(string s) { result = parsePosition(s) }
ArgumentPosition parseParamBody(string s) { result = AccessPath::parseInt(s) }
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
bindingset[s]
ParameterPosition parseArgBody(string s) { result = parsePosition(s) }
ParameterPosition parseArgBody(string s) { result = AccessPath::parseInt(s) }

View File

@@ -6,6 +6,15 @@
* (which does not use the shared data flow libraries).
*/
/**
* Convenience-predicate for extracting two capture groups at once.
*/
bindingset[input, regexp]
private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) {
capture1 = input.regexpCapture(regexp, 1) and
capture2 = input.regexpCapture(regexp, 2)
}
/** Companion module to the `AccessPath` class. */
module AccessPath {
/** A string that should be parsed as an access path. */
@@ -13,6 +22,95 @@ module AccessPath {
bindingset[this]
Range() { any() }
}
/**
* Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
* of the constant or any value contained in the interval.
*/
bindingset[arg]
int parseInt(string arg) {
result = arg.toInt()
or
// Match "n1..n2"
exists(string lo, string hi |
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.(-?\\d+)", lo, hi) and
result = [lo.toInt() .. hi.toInt()]
)
}
/**
* Parses a lower-bounded interval `n..` and gets the lower bound.
*/
bindingset[arg]
private int parseLowerBound(string arg) {
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
}
/**
* Parses an integer constant or interval (bounded or unbounded) that explicitly
* references the arity, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
private int parseIntWithExplicitArity(string arg, int arity) {
result >= 0 and // do not allow N-1 to resolve to a negative index
exists(string lo |
// N-x
lo = arg.regexpCapture("N-(\\d+)", 1) and
result = arity - lo.toInt()
or
// N-x..
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
result = [arity - lo.toInt(), arity - 1]
)
or
exists(string lo, string hi |
// x..N-y
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [lo.toInt() .. arity - hi.toInt()]
or
// N-x..N-y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. arity - hi.toInt()] and
result >= 0
or
// N-x..y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. hi.toInt()] and
result >= 0
)
}
/**
* Parses an integer constant or interval (bounded or unbounded) and gets any
* of the integers contained within (of which there may be infinitely many).
*
* Has no result for arguments involving an explicit arity, such as `N-1`.
*/
bindingset[arg, result]
int parseIntUnbounded(string arg) {
result = parseInt(arg)
or
result >= parseLowerBound(arg)
}
/**
* Parses an integer constant or interval (bounded or unbounded) that
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
int parseIntWithArity(string arg, int arity) {
result = parseInt(arg)
or
result in [parseLowerBound(arg) .. arity - 1]
or
result = parseIntWithExplicitArity(arg, arity)
}
}
/** Gets the `n`th token on the access path as a string. */

View File

@@ -274,7 +274,7 @@ API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) {
// use-node represents be an argument, and an edge originating from a def-node represents a parameter.
// We just map both to the same thing.
token.getName() = ["Argument", "Parameter"] and
result = node.getParameter(getAnIntFromStringUnbounded(token.getAnArgument()))
result = node.getParameter(AccessPath::parseIntUnbounded(token.getAnArgument()))
or
token.getName() = "ReturnValue" and
result = node.getReturn()
@@ -289,13 +289,9 @@ API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) {
bindingset[token]
API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathToken token) {
token.getName() = "Argument" and
(
result = invoke.getParameter(getAnIntFromStringUnbounded(token.getAnArgument()))
or
result =
invoke
.getParameter(getAnIntFromStringWithArity(token.getAnArgument(), invoke.getNumArgument()))
)
result =
invoke
.getParameter(AccessPath::parseIntWithArity(token.getAnArgument(), invoke.getNumArgument()))
or
token.getName() = "ReturnValue" and
result = invoke.getReturn()
@@ -310,7 +306,7 @@ API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathToken to
pragma[inline]
private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, AccessPathToken token) {
token.getName() = "WithArity" and
invoke.getNumArgument() = getAnIntFromStringUnbounded(token.getAnArgument())
invoke.getNumArgument() = AccessPath::parseIntUnbounded(token.getAnArgument())
or
Specific::invocationMatchesExtraCallSiteFilter(invoke, token)
}
@@ -361,89 +357,6 @@ Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPa
result = getInvocationFromPath(package, type, path, path.getNumToken())
}
/**
* Convenience-predicate for extracting two capture groups at once.
*/
bindingset[input, regexp]
private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) {
capture1 = input.regexpCapture(regexp, 1) and
capture2 = input.regexpCapture(regexp, 2)
}
/**
* Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
* of the constant or any value contained in the interval.
*/
bindingset[arg]
private int getAnIntFromString(string arg) {
result = arg.toInt()
or
// Match "n1..n2"
exists(string lo, string hi |
regexpCaptureTwo(arg, "(\\d+)\\.\\.(\\d+)", lo, hi) and
result = [lo.toInt() .. hi.toInt()]
)
}
/**
* Parses a lower-bounded interval `n..` and gets the lower bound.
*/
bindingset[arg]
private int getLowerBoundFromString(string arg) {
// Match "n.."
result = arg.regexpCapture("(\\d+)\\.\\.", 1).toInt()
}
/**
* Parses an integer constant or interval (bounded or unbounded) and gets any
* of the integers contained within (of which there may be infinitely many).
*
* Has no result for arguments involving an explicit arity, such as `N-1`.
*/
bindingset[arg, result]
private int getAnIntFromStringUnbounded(string arg) {
result = getAnIntFromString(arg)
or
result >= getLowerBoundFromString(arg)
}
/**
* Parses an integer constant or interval (bounded or unbounded) that explicitly
* references the arity, such as `N-1` or `N-3..N-1`.
*
* Note that such expressions will never resolve to a negative index, even if the
* arity is zero (it will have no result in that case).
*/
bindingset[arg, arity]
private int getAnIntFromStringWithArity(string arg, int arity) {
result >= 0 and // do not allow N-1 to resolve to a negative index
exists(string lo |
// N-x
lo = arg.regexpCapture("N-(\\d+)", 1) and
result = arity - lo.toInt()
or
// N-x..
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
result = [arity - lo.toInt(), arity - 1]
)
or
exists(string lo, string hi |
// x..N-y
regexpCaptureTwo(arg, "(\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [lo.toInt() .. arity - hi.toInt()]
or
// N-x..Ny
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. arity - hi.toInt()] and
result >= 0
or
// N-x..y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. hi.toInt()] and
result >= 0
)
}
/**
* Module providing access to the imported models in terms of API graph nodes.
*/

View File

@@ -32,12 +32,18 @@ module SummaryComponent {
/** Gets a summary component that represents an element in an array at an unknown index. */
SummaryComponent arrayElementUnknown() { result = SC::content(TUnknownArrayElementContent()) }
/** Gets a summary component that represents an element in an array at a known index. */
/**
* Gets a summary component that represents an element in an array at a known index.
*
* Has no result for negative indices. Wrap-around interpretation of negative indices should be
* handled by the caller, if modeling a function that has such behavior.
*/
bindingset[i]
SummaryComponent arrayElementKnown(int i) {
result = SC::content(TKnownArrayElementContent(i))
or
// `i` may be out of range
i >= 0 and
not exists(TKnownArrayElementContent(i)) and
result = arrayElementUnknown()
}

View File

@@ -6,6 +6,15 @@
* (which does not use the shared data flow libraries).
*/
/**
* Convenience-predicate for extracting two capture groups at once.
*/
bindingset[input, regexp]
private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) {
capture1 = input.regexpCapture(regexp, 1) and
capture2 = input.regexpCapture(regexp, 2)
}
/** Companion module to the `AccessPath` class. */
module AccessPath {
/** A string that should be parsed as an access path. */
@@ -13,6 +22,95 @@ module AccessPath {
bindingset[this]
Range() { any() }
}
/**
* Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
* of the constant or any value contained in the interval.
*/
bindingset[arg]
int parseInt(string arg) {
result = arg.toInt()
or
// Match "n1..n2"
exists(string lo, string hi |
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.(-?\\d+)", lo, hi) and
result = [lo.toInt() .. hi.toInt()]
)
}
/**
* Parses a lower-bounded interval `n..` and gets the lower bound.
*/
bindingset[arg]
private int parseLowerBound(string arg) {
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
}
/**
* Parses an integer constant or interval (bounded or unbounded) that explicitly
* references the arity, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
private int parseIntWithExplicitArity(string arg, int arity) {
result >= 0 and // do not allow N-1 to resolve to a negative index
exists(string lo |
// N-x
lo = arg.regexpCapture("N-(\\d+)", 1) and
result = arity - lo.toInt()
or
// N-x..
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
result = [arity - lo.toInt(), arity - 1]
)
or
exists(string lo, string hi |
// x..N-y
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [lo.toInt() .. arity - hi.toInt()]
or
// N-x..N-y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. arity - hi.toInt()] and
result >= 0
or
// N-x..y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. hi.toInt()] and
result >= 0
)
}
/**
* Parses an integer constant or interval (bounded or unbounded) and gets any
* of the integers contained within (of which there may be infinitely many).
*
* Has no result for arguments involving an explicit arity, such as `N-1`.
*/
bindingset[arg, result]
int parseIntUnbounded(string arg) {
result = parseInt(arg)
or
result >= parseLowerBound(arg)
}
/**
* Parses an integer constant or interval (bounded or unbounded) that
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
int parseIntWithArity(string arg, int arity) {
result = parseInt(arg)
or
result in [parseLowerBound(arg) .. arity - 1]
or
result = parseIntWithExplicitArity(arg, arity)
}
}
/** Gets the `n`th token on the access path as a string. */

View File

@@ -59,7 +59,7 @@ predicate summaryElement(DataFlowCallable c, string input, string output, string
* is currently restricted to `"BlockArgument"`.
*/
bindingset[c]
SummaryComponent interpretComponentSpecific(string c) {
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
c = "Receiver" and
result = FlowSummary::SummaryComponent::receiver()
or
@@ -76,15 +76,10 @@ SummaryComponent interpretComponentSpecific(string c) {
result = FlowSummary::SummaryComponent::arrayElementUnknown()
or
exists(int i |
c.regexpCapture("ArrayElement\\[([0-9]+)\\]", 1).toInt() = i and
c.getName() = "ArrayElement" and
i = AccessPath::parseInt(c.getAnArgument()) and
result = FlowSummary::SummaryComponent::arrayElementKnown(i)
)
or
exists(int i1, int i2 |
c.regexpCapture("ArrayElement\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = i1 and
c.regexpCapture("ArrayElement\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = i2 and
result = FlowSummary::SummaryComponent::arrayElementKnown([i1 .. i2])
)
}
/** Gets the textual representation of a summary component in the format used for flow summaries. */
@@ -172,25 +167,14 @@ module ParsePositions {
)
}
bindingset[s]
private int parsePosition(string s) {
result = s.regexpCapture("([-0-9]+)", 1).toInt()
or
exists(int n1, int n2 |
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 1).toInt() = n1 and
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 2).toInt() = n2 and
result in [n1 .. n2]
)
}
predicate isParsedParameterPosition(string c, int i) {
isParamBody(c) and
i = parsePosition(c)
i = AccessPath::parseInt(c)
}
predicate isParsedArgumentPosition(string c, int i) {
isArgBody(c) and
i = parsePosition(c)
i = AccessPath::parseInt(c)
}
}