mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Shared: Add library for unbound lists
This commit is contained in:
@@ -224,25 +224,17 @@ signature module InputSig1<LocationSig Location> {
|
||||
|
||||
module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
private import Input1
|
||||
private import codeql.util.UnboundList as UnboundListImpl
|
||||
|
||||
private module TypeParameter {
|
||||
private import codeql.util.DenseRank
|
||||
private module UnboundListInput implements UnboundListImpl::InputSig<Location> {
|
||||
class Element = TypeParameter;
|
||||
|
||||
private module DenseRankInput implements DenseRankInputSig {
|
||||
class Ranked = TypeParameter;
|
||||
predicate getId = getTypeParameterId/1;
|
||||
|
||||
predicate getRank = getTypeParameterId/1;
|
||||
}
|
||||
|
||||
int getRank(TypeParameter tp) { tp = DenseRank<DenseRankInput>::denseRank(result) }
|
||||
|
||||
string encode(TypeParameter tp) { result = getRank(tp).toString() }
|
||||
|
||||
bindingset[s]
|
||||
TypeParameter decode(string s) { encode(result) = s }
|
||||
predicate getLengthLimit = getTypePathLimit/0;
|
||||
}
|
||||
|
||||
final private class String = string;
|
||||
private import UnboundListImpl::Make<Location, UnboundListInput>
|
||||
|
||||
/**
|
||||
* A path into a type.
|
||||
@@ -274,101 +266,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
* implementation uses unique type parameter identifiers, in order to not mix
|
||||
* up type parameters from different types.
|
||||
*/
|
||||
class TypePath extends String {
|
||||
bindingset[this]
|
||||
TypePath() { exists(this) }
|
||||
|
||||
bindingset[this]
|
||||
private TypeParameter getTypeParameter(int i) {
|
||||
result = TypeParameter::decode(this.splitAt(".", i))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this type path. */
|
||||
bindingset[this]
|
||||
string toString() {
|
||||
result =
|
||||
concat(int i, TypeParameter tp |
|
||||
tp = this.getTypeParameter(i)
|
||||
|
|
||||
tp.toString(), "." order by i
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this type path is empty. */
|
||||
predicate isEmpty() { this = "" }
|
||||
|
||||
/** Gets the length of this path. */
|
||||
bindingset[this]
|
||||
pragma[inline_late]
|
||||
int length() {
|
||||
// Same as
|
||||
// `result = count(this.indexOf("."))`
|
||||
// but performs better because it doesn't use an aggregate
|
||||
result = this.regexpReplaceAll("[0-9]+", "").length()
|
||||
}
|
||||
|
||||
/** Gets the path obtained by appending `suffix` onto this path. */
|
||||
bindingset[this, suffix]
|
||||
TypePath append(TypePath suffix) {
|
||||
result = this + suffix and
|
||||
(
|
||||
not exists(getTypePathLimit())
|
||||
or
|
||||
result.length() <= getTypePathLimit()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path obtained by appending `suffix` onto this path.
|
||||
*
|
||||
* Unlike `append`, this predicate has `result` in the binding set,
|
||||
* so there is no need to check the length of `result`.
|
||||
*/
|
||||
bindingset[this, result]
|
||||
TypePath appendInverse(TypePath suffix) { suffix = result.stripPrefix(this) }
|
||||
|
||||
/** Gets the path obtained by removing `prefix` from this path. */
|
||||
bindingset[this, prefix]
|
||||
TypePath stripPrefix(TypePath prefix) { this = prefix + result }
|
||||
|
||||
/** Holds if this path starts with `tp`, followed by `suffix`. */
|
||||
bindingset[this]
|
||||
predicate isCons(TypeParameter tp, TypePath suffix) {
|
||||
exists(string regexp | regexp = "([0-9]+)\\.(.*)" |
|
||||
tp = TypeParameter::decode(this.regexpCapture(regexp, 1)) and
|
||||
suffix = this.regexpCapture(regexp, 2)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this path starts with `prefix`, followed by `tp`. */
|
||||
bindingset[this]
|
||||
predicate isSnoc(TypePath prefix, TypeParameter tp) {
|
||||
exists(string regexp | regexp = "(|.+\\.)([0-9]+)\\." |
|
||||
prefix = this.regexpCapture(regexp, 1) and
|
||||
tp = TypeParameter::decode(this.regexpCapture(regexp, 2))
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the head of this path, if any. */
|
||||
bindingset[this]
|
||||
TypeParameter getHead() { result = this.getTypeParameter(0) }
|
||||
}
|
||||
class TypePath = UnboundList;
|
||||
|
||||
/** Provides predicates for constructing `TypePath`s. */
|
||||
module TypePath {
|
||||
/** Gets the empty type path. */
|
||||
TypePath nil() { result.isEmpty() }
|
||||
|
||||
/** Gets the singleton type path `tp`. */
|
||||
TypePath singleton(TypeParameter tp) { result = TypeParameter::encode(tp) + "." }
|
||||
|
||||
/**
|
||||
* Gets the type path obtained by appending the singleton type path `tp`
|
||||
* onto `suffix`.
|
||||
*/
|
||||
bindingset[suffix]
|
||||
TypePath cons(TypeParameter tp, TypePath suffix) { result = singleton(tp).append(suffix) }
|
||||
}
|
||||
module TypePath = UnboundList;
|
||||
|
||||
/**
|
||||
* A class that has a type tree associated with it.
|
||||
@@ -600,11 +501,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
|
||||
private TypeParameter getNthTypeParameter(TypeAbstraction abs, int i) {
|
||||
result =
|
||||
rank[i + 1](TypeParameter tp |
|
||||
tp = abs.getATypeParameter()
|
||||
|
|
||||
tp order by TypeParameter::getRank(tp)
|
||||
)
|
||||
rank[i + 1](TypeParameter tp | tp = abs.getATypeParameter() | tp order by getRank(tp))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user