Skip to content
Merged
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
47 changes: 42 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,43 @@ 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() }
/** Gets the ASCII printable excluding `.` with zero-based index `code`. */
pragma[nomagic]
Comment thread
hvitved marked this conversation as resolved.
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(_)) }

/**
* Gets the `i`th digit (modulo `asciiCodes()`) in a base-`asciiCodes()` integer
* representation of `getRank(e)`.
*/
private int getAsciiCodePart(Element e, int i) {
Comment thread
hvitved marked this conversation as resolved.
result = getRank(e) and
i = 0
or
exists(int mid |
mid = getAsciiCodePart(e, i - 1) and
result = mid / asciiCodes() and
result > 0
)
}

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 +125,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 +160,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 +170,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 +185,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