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
4 changes: 4 additions & 0 deletions rust/ql/lib/change-notes/2025-10-06-call-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: majorAnalysis
---
* Resolution of calls to functions has been improved in a number of ways, to make it more aligned with the behavior of the Rust compiler. This may impact queries that rely on call resolution, such as data flow queries.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
* the canonical path `path` and the method name `method`, and if it borrows its
* first `borrows` arguments.
*/
private predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
arity = 1 and
(
// Negation
Expand Down
3 changes: 3 additions & 0 deletions rust/ql/lib/codeql/rust/elements/internal/TypeParamImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ module Impl {
*/
TypeBound getATypeBound() { result = this.getTypeBound(_) }

/** Holds if this type parameter has at least one type bound. */
predicate hasTypeBound() { exists(this.getATypeBound()) }

override string toAbbreviatedString() { result = this.getName().getText() }

override string toStringImpl() { result = this.getName().getText() }
Expand Down
93 changes: 93 additions & 0 deletions rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,96 @@ class StringStruct extends Struct {
pragma[nomagic]
StringStruct() { this.getCanonicalPath() = "alloc::string::String" }
}

/**
* The [`Deref` trait][1].
*
* [1]: https://doc.rust-lang.org/core/ops/trait.Deref.html
*/
class DerefTrait extends Trait {
pragma[nomagic]
DerefTrait() { this.getCanonicalPath() = "core::ops::deref::Deref" }

/** Gets the `deref` function. */
Function getDerefFunction() { result = this.(TraitItemNode).getAssocItem("deref") }

/** Gets the `Target` associated type. */
pragma[nomagic]
TypeAlias getTargetType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Target"
}
}

/**
* The [`Index` trait][1].
*
* [1]: https://doc.rust-lang.org/std/ops/trait.Index.html
*/
class IndexTrait extends Trait {
pragma[nomagic]
IndexTrait() { this.getCanonicalPath() = "core::ops::index::Index" }

/** Gets the `index` function. */
Function getIndexFunction() { result = this.(TraitItemNode).getAssocItem("index") }

/** Gets the `Output` associated type. */
pragma[nomagic]
TypeAlias getOutputType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Output"
}
}

/**
* The [`Box` struct][1].
*
* [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html
*/
class BoxStruct extends Struct {
pragma[nomagic]
BoxStruct() { this.getCanonicalPath() = "alloc::boxed::Box" }
}

/**
* The [`Rc` struct][1].
*
* [1]: https://doc.rust-lang.org/std/rc/struct.Rc.html
*/
class RcStruct extends Struct {
pragma[nomagic]
RcStruct() { this.getCanonicalPath() = "alloc::rc::Rc" }
}

/**
* The [`Arc` struct][1].
*
* [1]: https://doc.rust-lang.org/std/sync/struct.Arc.html
*/
class ArcStruct extends Struct {
pragma[nomagic]
ArcStruct() { this.getCanonicalPath() = "alloc::sync::Arc" }
}

/**
* The [`Pin` struct][1].
*
* [1]: https://doc.rust-lang.org/std/pin/struct.Pin.html
*/
class PinStruct extends Struct {
pragma[nomagic]
PinStruct() { this.getCanonicalPath() = "core::pin::Pin" }
}

/**
* The [`Vec` struct][1].
*
* [1]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html
*/
class Vec extends Struct {
pragma[nomagic]
Vec() { this.getCanonicalPath() = "alloc::vec::Vec" }

/** Gets the type parameter representing the element type. */
TypeParam getElementTypeParam() { result = this.getGenericParamList().getTypeParam(0) }
}
62 changes: 47 additions & 15 deletions rust/ql/lib/codeql/rust/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
}
}

final private class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
final class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
pragma[nomagic]
Path getABoundPath() {
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
Expand Down Expand Up @@ -963,7 +963,9 @@ final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof T
Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() }

pragma[nomagic]
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
ItemNode resolveBound(Path path) { path = this.getABoundPath() and result = resolvePath(path) }

ItemNode resolveABound() { result = this.resolveBound(_) }

override AssocItemNode getAnAssocItem() { result = this.getADescendant() }

Expand Down Expand Up @@ -1643,25 +1645,55 @@ signature predicate relevantTraitVisibleSig(Element element, Trait trait);
* at a given element.
*/
module TraitIsVisible<relevantTraitVisibleSig/2 relevantTraitVisible> {
/** Holds if the trait might be looked up in `encl`. */
private predicate traitLookup(ItemNode encl, Element element, Trait trait) {
// lookup in immediately enclosing item
relevantTraitVisible(element, trait) and
encl.getADescendant() = element
private newtype TNode =
TTrait(Trait t) { relevantTraitVisible(_, t) } or
TItemNode(ItemNode i) or
TElement(Element e) { relevantTraitVisible(e, _) }

private predicate isTrait(TNode n) { n instanceof TTrait }

private predicate step(TNode n1, TNode n2) {
exists(Trait t1, ItemNode i2 |
n1 = TTrait(t1) and
n2 = TItemNode(i2) and
t1 = i2.getASuccessor(_, _, _)
)
or
// lookup in an outer scope, but only if the trait is not declared in inner scope
exists(ItemNode mid |
traitLookup(mid, element, trait) and
not trait = mid.getASuccessor(_, _, _) and
encl = getOuterScope(mid)
exists(ItemNode i1, ItemNode i2 |
n1 = TItemNode(i1) and
n2 = TItemNode(i2) and
i1 = getOuterScope(i2)
)
or
exists(ItemNode i1, Element e2 |
n1 = TItemNode(i1) and
n2 = TElement(e2) and
i1.getADescendant() = e2
)
}

private predicate isElement(TNode n) { n instanceof TElement }

private predicate traitIsVisibleTC(TNode trait, TNode element) =
doublyBoundedFastTC(step/2, isTrait/1, isElement/1)(trait, element)

pragma[nomagic]
private predicate relevantTraitVisibleLift(TNode trait, TElement element) {
exists(Trait t, Element e |
trait = TTrait(t) and
element = TElement(e) and
relevantTraitVisible(e, t)
)
}

/** Holds if the trait `trait` is visible at `element`. */
pragma[nomagic]
predicate traitIsVisible(Element element, Trait trait) {
exists(ItemNode encl |
traitLookup(encl, element, trait) and trait = encl.getASuccessor(_, _, _)
exists(TNode t, TNode e |
traitIsVisibleTC(t, e) and
relevantTraitVisibleLift(t, e) and
t = TTrait(trait) and
e = TElement(element)
)
}
}
Expand Down Expand Up @@ -2101,7 +2133,7 @@ private predicate builtin(string name, ItemNode i) {

/** Provides predicates for debugging the path resolution implementation. */
private module Debug {
private Locatable getRelevantLocatable() {
Locatable getRelevantLocatable() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
filepath.matches("%/main.rs") and
Expand Down
25 changes: 25 additions & 0 deletions rust/ql/lib/codeql/rust/internal/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ private import TypeMention
private import codeql.rust.internal.CachedStages
private import codeql.rust.elements.internal.generated.Raw
private import codeql.rust.elements.internal.generated.Synth
private import codeql.rust.frameworks.stdlib.Stdlib

/**
* Holds if a dyn trait type should have a type parameter associated with `n`. A
Expand Down Expand Up @@ -624,3 +625,27 @@ final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeR
implTraitTypeParam(this, _, result.(TypeParamTypeParameter).getTypeParam())
}
}

/**
* Holds if `root` is a valid complex [`self` root type][1], with type
* parameter `tp`.
*
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-items.associated.fn.method.self-ty
*/
pragma[nomagic]
predicate complexSelfRoot(Type root, TypeParameter tp) {
tp = root.(RefType).getPositionalTypeParameter(_)
or
exists(Struct s |
root = TStruct(s) and
tp = root.getPositionalTypeParameter(0)
|
s instanceof BoxStruct
or
s instanceof RcStruct
or
s instanceof ArcStruct
or
s instanceof PinStruct
)
}
Loading
Loading