Skip to content
Draft
Show file tree
Hide file tree
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
44 changes: 23 additions & 21 deletions rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2477,10 +2477,10 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
additional predicate decodeDerefChainBorrow(
string derefChainBorrow, DerefChain derefChain, BorrowKind borrow
) {
exists(string regexp |
regexp = "^(.*);(.*)$" and
derefChain = derefChainBorrow.regexpCapture(regexp, 1) and
borrow.toString() = derefChainBorrow.regexpCapture(regexp, 2)
exists(int i |
i = derefChainBorrow.indexOf(";") and
derefChain = derefChainBorrow.prefix(i) and
borrow.toString() = derefChainBorrow.suffix(i + 1)
)
}

Expand Down Expand Up @@ -2604,37 +2604,39 @@ private Type inferMethodCallTypeNonSelf(AstNode n, boolean isReturn, TypePath pa
}

/**
* Gets the type of `n` at `path` after applying `derefChain` and `borrow`,
* where `n` is the `self` argument of a method call.
* Gets the type of `n` at `path` after applying `derefChain`, where `n` is the
* `self` argument of a method call.
*
* The predicate recursively pops the head of `derefChain` until it becomes
* empty, at which point the inferred type can be applied back to `n`.
*/
pragma[nomagic]
private Type inferMethodCallTypeSelf(
AstNode n, DerefChain derefChain, BorrowKind borrow, TypePath path
) {
exists(MethodCallMatchingInput::AccessPosition apos, string derefChainBorrow |
result = inferMethodCallType0(_, apos, n, derefChainBorrow, path) and
private Type inferMethodCallTypeSelf(AstNode n, DerefChain derefChain, TypePath path) {
exists(
MethodCallMatchingInput::AccessPosition apos, string derefChainBorrow, BorrowKind borrow,
TypePath path0
|
result = inferMethodCallType0(_, apos, n, derefChainBorrow, path0) and
apos.isSelf() and
MethodCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow)
)
or
// adjust for implicit borrow
exists(TypePath path0, BorrowKind borrow0 |
result = inferMethodCallTypeSelf(n, derefChain, borrow0, path0) and
path0.isCons(borrow0.getRefType().getPositionalTypeParameter(0), path) and
borrow.isNoBorrow()
|
borrow.isNoBorrow() and
path = path0
or
// adjust for implicit borrow
exists(TypePath prefix |
prefix = TypePath::singleton(borrow.getRefType().getPositionalTypeParameter(0)) and
path0 = prefix.appendInverse(path)
)
)
or
// adjust for implicit deref
exists(
DerefChain derefChain0, Type t0, TypePath path0, DerefImplItemNode impl, Type selfParamType,
TypePath selfPath
|
t0 = inferMethodCallTypeSelf(n, derefChain0, borrow, path0) and
t0 = inferMethodCallTypeSelf(n, derefChain0, path0) and
derefChain0.isCons(impl, derefChain) and
borrow.isNoBorrow() and
selfParamType = impl.resolveSelfTypeAt(selfPath)
|
result = selfParamType and
Expand All @@ -2653,7 +2655,7 @@ private Type inferMethodCallTypeSelf(
private Type inferMethodCallTypePreCheck(AstNode n, boolean isReturn, TypePath path) {
result = inferMethodCallTypeNonSelf(n, isReturn, path)
or
result = inferMethodCallTypeSelf(n, DerefChain::nil(), TNoBorrowKind(), path) and
result = inferMethodCallTypeSelf(n, DerefChain::nil(), path) and
isReturn = false
}

Expand Down
21 changes: 14 additions & 7 deletions shared/util/codeql/util/UnboundList.qll
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ module Make<LocationSig Location, InputSig<Location> Input> {
/** Holds if this list is empty. */
predicate isEmpty() { this = "" }

bindingset[this]
private int stringLength() { result = super.length() }

/** Gets the length of this list. */
bindingset[this]
pragma[inline_late]
Expand Down Expand Up @@ -115,19 +118,23 @@ module Make<LocationSig Location, InputSig<Location> Input> {
/** Holds if this list starts with `e`, followed by `suffix`. */
bindingset[this]
predicate isCons(Element e, UnboundList suffix) {
exists(string regexp | regexp = "^([0-9]+)\\.(.*)$" |
e = decode(this.regexpCapture(regexp, 1)) and
suffix = this.regexpCapture(regexp, 2)
exists(string elem |
// it is more efficient to not create a capture group for the suffix, since
// `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
e = decode(elem) and
suffix = this.suffix(elem.length() + 1)
)
}

/** Holds if this list starts with `prefix`, followed by `e`. */
bindingset[this]
predicate isSnoc(UnboundList prefix, Element e) {
exists(string regexp | regexp = "^(|.+\\.)([0-9]+)\\.$" |
prefix = this.regexpCapture(regexp, 1) and
e = decode(this.regexpCapture(regexp, 2))
)
// same remark as above about not using multiple capture groups
prefix = this.regexpCapture("^(|.+\\.)[0-9]+\\.$", 1) and
e = decode(this.substring(prefix.stringLength(), this.stringLength() - 1))
}

/** Gets the head of this list, if any. */
Expand Down
Loading