Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions shared/util/codeql/util/UnboundList.qll
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ overlay[local?]
module;

private import Location
private import Strings

/** Provides the input to `Make`. */
signature module InputSig<LocationSig Location> {
Expand Down Expand Up @@ -52,7 +53,38 @@ module Make<LocationSig Location, InputSig<Location> Input> {
/** Gets the rank of element `e`, which is used internally in the string encoding. */
int getRank(Element e) { e = DenseRank<DenseRankInput>::denseRank(result) }

private string encode(Element e) { result = getRank(e).toString() }
pragma[nomagic]
private string interpretAsciiCode(int code) {
exists(int dot, int c |
c = code + 1 and
// `.` is used as element separator, so cannot be used to encode elements
dot = asciiPrintable(".") and
if c < dot then c = asciiPrintable(result) else c + 1 = asciiPrintable(result)
)
}

private int asciiCodes() { result = strictcount(interpretAsciiCode(_)) }

private int getAsciiCodePart(Element e, int i) {
result = getRank(e) and
i = 0
or
exists(int mid |
mid = getAsciiCodePart(e, i - 1) and
mid > 0 and
result = mid / asciiCodes()
)
Comment on lines +72 to +76
}

pragma[nomagic]
private string encode(Element e) {
result =
strictconcat(string s, int i |
s = interpretAsciiCode(getAsciiCodePart(e, i) % asciiCodes())
|
s order by i
)
}

bindingset[s]
private Element decode(string s) { encode(result) = s }
Expand Down Expand Up @@ -88,7 +120,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
// Same as
// `result = count(this.indexOf("."))`
// but performs better because it doesn't use an aggregate
result = this.regexpReplaceAll("[0-9]+", "").length()
result = this.regexpReplaceAll("[^\\.]+", "").length()
}

/** Gets the list obtained by appending `suffix` onto this list. */
Expand Down Expand Up @@ -123,7 +155,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
// `regexpCapture` will then always join in both groups, only to afterwards filter
// based on the requested group (the group number is not part of the binding set
// of `regexpCapture`)
elem = this.regexpCapture("^([0-9]+)\\..*$", 1) and
elem = this.regexpCapture("^([^\\.]+)\\..*$", 1) and
e = decode(elem) and
suffix = this.suffix(elem.length() + 1)
)
Expand All @@ -133,7 +165,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
bindingset[this]
predicate isSnoc(UnboundList prefix, Element e) {
// same remark as above about not using multiple capture groups
prefix = this.regexpCapture("^(|.+\\.)[0-9]+\\.$", 1) and
prefix = this.regexpCapture("^(|.+\\.)[^\\.]+\\.$", 1) and
e = decode(this.substring(prefix.stringLength(), this.stringLength() - 1))
}

Expand All @@ -148,7 +180,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
*/
bindingset[this]
UnboundList getProperPrefix(int i) {
exists(string regexp, int occurrenceOffset | regexp = "[0-9]+\\." |
exists(string regexp, int occurrenceOffset | regexp = "[^\\.]+\\." |
exists(this.regexpFind(regexp, i, occurrenceOffset)) and
result = this.prefix(occurrenceOffset)
)
Expand Down
Loading