Skip to content

Rust: Path resolution for extern crates #19614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 10, 2025
Merged
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
61 changes: 54 additions & 7 deletions rust/ql/lib/codeql/rust/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,25 @@ abstract class ItemNode extends Locatable {
or
crateDependencyEdge(this, name, result)
or
externCrateEdge(this, name, result)
or
// items made available through `use` are available to nodes that contain the `use`
exists(UseItemNode use |
use = this.getASuccessorRec(_) and
result = use.(ItemNode).getASuccessorRec(name)
)
or
exists(ExternCrateItemNode ec | result = ec.(ItemNode).getASuccessorRec(name) |
ec = this.getASuccessorRec(_)
or
// if the extern crate appears in the crate root, then the crate name is also added
// to the 'extern prelude', see https://doc.rust-lang.org/reference/items/extern-crates.html
exists(Crate c |
ec = c.getSourceFile().(ItemNode).getASuccessorRec(_) and
this = c.getASourceFile()
)
)
or
// items made available through macro calls are available to nodes that contain the macro call
exists(MacroCallItemNode call |
call = this.getASuccessorRec(_) and
Expand Down Expand Up @@ -353,16 +366,30 @@ class CrateItemNode extends ItemNode instanceof Crate {

override predicate providesCanonicalPathPrefixFor(Crate c, ItemNode child) {
this.hasCanonicalPath(c) and
exists(ModuleLikeNode m |
child.getImmediateParent() = m and
not m = child.(SourceFileItemNode).getSuper() and
m = super.getSourceFile()
exists(SourceFileItemNode file |
child.getImmediateParent() = file and
not file = child.(SourceFileItemNode).getSuper() and
file = super.getSourceFile()
)
}

override string getCanonicalPath(Crate c) { c = this and result = Crate.super.getName() }
}

class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
override string getName() { result = super.getRename().getName().getText() }

override Namespace getNamespace() { none() }

override Visibility getVisibility() { none() }

override TypeParam getTypeParam(int i) { none() }

override predicate hasCanonicalPath(Crate c) { none() }

override string getCanonicalPath(Crate c) { none() }
}

/** An item that can occur in a trait or an `impl` block. */
abstract private class AssocItemNode extends ItemNode, AssocItem {
/** Holds if this associated item has an implementation. */
Expand Down Expand Up @@ -793,6 +820,10 @@ class TypeAliasItemNode extends AssocItemNode instanceof TypeAlias {
override Visibility getVisibility() { result = TypeAlias.super.getVisibility() }

override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }

override predicate hasCanonicalPath(Crate c) { none() }

override string getCanonicalPath(Crate c) { none() }
}

private class UnionItemNode extends ItemNode instanceof Union {
Expand Down Expand Up @@ -1063,12 +1094,12 @@ private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
}

/**
* Holds if `m` depends on crate `dep` named `name`.
* Holds if `file` depends on crate `dep` named `name`.
*/
private predicate crateDependencyEdge(ModuleLikeNode m, string name, CrateItemNode dep) {
private predicate crateDependencyEdge(SourceFileItemNode file, string name, CrateItemNode dep) {
exists(CrateItemNode c |
dep = c.(Crate).getDependency(name) and
m = c.getASourceFile()
file = c.getASourceFile()
)
}

Expand Down Expand Up @@ -1404,6 +1435,22 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
)
}

/** Holds if `ec` imports `crate` as `name`. */
pragma[nomagic]
private predicate externCrateEdge(ExternCrateItemNode ec, string name, CrateItemNode crate) {
name = ec.getName() and
exists(SourceFile f, string s |
ec.getFile() = f.getFile() and
s = ec.(ExternCrate).getIdentifier().getText()
|
crateDependencyEdge(f, s, crate)
or
// `extern crate` is used to import the current crate
s = "self" and
ec.getFile() = crate.getASourceFile().getFile()
)
}

/**
* Holds if `i` is available inside `f` because it is reexported in
* [the `core` prelude][1] or [the `std` prelude][2].
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,64 @@
multiplePathResolutions
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
multipleCanonicalPaths
| file://:0:0:0:0 | fn to_ordering | file://:0:0:0:0 | Crate([email protected]) | <typenum::Equal as core::cmp::Ord>::to_ordering |
| file://:0:0:0:0 | fn to_ordering | file://:0:0:0:0 | Crate([email protected]) | <typenum::Equal as typenum::marker_traits::Ord>::to_ordering |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
multiplePathResolutions
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ edges
| main.rs:57:11:57:26 | source_slice(...) | main.rs:57:6:57:7 | s1 | provenance | |
| main.rs:58:6:58:7 | s2 | main.rs:59:7:59:8 | s2 | provenance | |
| main.rs:58:11:58:24 | s1.to_string() | main.rs:58:6:58:7 | s2 | provenance | |
| main.rs:63:9:63:9 | s | main.rs:64:16:64:16 | s | provenance | |
| main.rs:63:9:63:9 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:3 |
| main.rs:63:13:63:22 | source(...) | main.rs:63:9:63:9 | s | provenance | |
| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:3 |
| main.rs:68:9:68:9 | s | main.rs:70:34:70:61 | MacroExpr | provenance | |
| main.rs:68:9:68:9 | s | main.rs:73:34:73:59 | MacroExpr | provenance | |
| main.rs:68:13:68:22 | source(...) | main.rs:68:9:68:9 | s | provenance | |
Expand Down Expand Up @@ -75,6 +77,7 @@ nodes
| main.rs:59:7:59:8 | s2 | semmle.label | s2 |
| main.rs:63:9:63:9 | s | semmle.label | s |
| main.rs:63:13:63:22 | source(...) | semmle.label | source(...) |
| main.rs:64:16:64:16 | s | semmle.label | s |
| main.rs:64:16:64:25 | s.as_str() | semmle.label | s.as_str() |
| main.rs:68:9:68:9 | s | semmle.label | s |
| main.rs:68:13:68:22 | source(...) | semmle.label | source(...) |
Expand Down
5 changes: 4 additions & 1 deletion rust/ql/test/library-tests/path-resolution/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ mod m13 {
pub struct f {} // I72

mod m14 {
use crate::m13::f; // $ item=I71 item=I72
use zelf::m13::f; // $ item=I71 item=I72

#[rustfmt::skip]
fn g(x: f) { // $ item=I72
Expand Down Expand Up @@ -621,6 +621,8 @@ mod m24 {
} // I121
}

extern crate self as zelf;

fn main() {
my::nested::nested1::nested2::f(); // $ item=I4
my::f(); // $ item=I38
Expand Down Expand Up @@ -650,4 +652,5 @@ fn main() {
m18::m19::m20::g(); // $ item=I103
m23::f(); // $ item=I108
m24::f(); // $ item=I121
zelf::h(); // $ item=I25
}
2 changes: 1 addition & 1 deletion rust/ql/test/library-tests/path-resolution/my.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Result<
T, // T
> = ::std::result::Result<
T, // $ item=T
String,> // $ item=Result
String,> // $ item=Result $ item=String
; // my::Result

fn int_div(
Expand Down
Loading