Skip to content

Rust: Path resolution for inherited associated items #18808

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 3 commits into from
Feb 19, 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
29 changes: 25 additions & 4 deletions rust/ql/lib/codeql/rust/elements/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ abstract class ItemNode extends AstNode {
call = this.getASuccessorRec(_) and
result = call.(ItemNode).getASuccessorRec(name)
)
or
// a trait has access to the associated items of its supertraits
result = this.(TraitItemNode).resolveABound().getASuccessorRec(name) and
result instanceof AssocItemNode
or
// items made available by an implementation where `this` is the implementing type
exists(ItemNode node |
this = node.(ImplItemNode).resolveSelfTy() and
result = node.getASuccessorRec(name) and
result instanceof AssocItemNode
)
}

/** Gets a successor named `name` of this item, if any. */
Expand Down Expand Up @@ -179,7 +190,10 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
override Visibility getVisibility() { none() }
}

private class ConstItemNode extends ItemNode instanceof Const {
/** An item that can occur in a trait or an `impl` block. */
abstract private class AssocItemNode extends ItemNode { }

private class ConstItemNode extends AssocItemNode instanceof Const {
override string getName() { result = Const.super.getName().getText() }

override Namespace getNamespace() { result.isValue() }
Expand All @@ -205,7 +219,7 @@ private class VariantItemNode extends ItemNode instanceof Variant {
override Visibility getVisibility() { result = Variant.super.getVisibility() }
}

private class FunctionItemNode extends ItemNode instanceof Function {
private class FunctionItemNode extends AssocItemNode instanceof Function {
override string getName() { result = Function.super.getName().getText() }

override Namespace getNamespace() { result.isValue() }
Expand Down Expand Up @@ -239,7 +253,7 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
override Visibility getVisibility() { result = Impl.super.getVisibility() }
}

private class MacroCallItemNode extends ItemNode instanceof MacroCall {
private class MacroCallItemNode extends AssocItemNode instanceof MacroCall {
override string getName() { result = "(macro call)" }

override Namespace getNamespace() { none() }
Expand Down Expand Up @@ -269,14 +283,21 @@ private class StructItemNode extends ItemNode instanceof Struct {
}

class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
pragma[nomagic]
Path getABoundPath() {
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
}

ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }

override string getName() { result = Trait.super.getName().getText() }

override Namespace getNamespace() { result.isType() }

override Visibility getVisibility() { result = Trait.super.getVisibility() }
}

class TypeAliasItemNode extends ItemNode instanceof TypeAlias {
class TypeAliasItemNode extends AssocItemNode instanceof TypeAlias {
override string getName() { result = TypeAlias.super.getName().getText() }

override Namespace getNamespace() { result.isType() }
Expand Down
21 changes: 21 additions & 0 deletions rust/ql/test/library-tests/dataflow/global/inline-flow.expected
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ edges
| main.rs:103:13:103:30 | mn.data_through(...) | main.rs:103:9:103:9 | b | provenance | |
| main.rs:103:29:103:29 | a | main.rs:79:28:79:33 | ...: i64 | provenance | |
| main.rs:103:29:103:29 | a | main.rs:103:13:103:30 | mn.data_through(...) | provenance | |
| main.rs:109:9:109:9 | a | main.rs:110:26:110:26 | a | provenance | |
| main.rs:109:13:109:21 | source(...) | main.rs:109:9:109:9 | a | provenance | |
| main.rs:110:26:110:26 | a | main.rs:67:23:67:28 | ...: i64 | provenance | |
| main.rs:115:9:115:9 | a | main.rs:116:39:116:39 | a | provenance | |
| main.rs:115:13:115:22 | source(...) | main.rs:115:9:115:9 | a | provenance | |
| main.rs:116:9:116:9 | b | main.rs:117:10:117:10 | b | provenance | |
| main.rs:116:13:116:40 | ...::data_through(...) | main.rs:116:9:116:9 | b | provenance | |
| main.rs:116:39:116:39 | a | main.rs:79:28:79:33 | ...: i64 | provenance | |
| main.rs:116:39:116:39 | a | main.rs:116:13:116:40 | ...::data_through(...) | provenance | |
| main.rs:128:12:128:17 | ...: i64 | main.rs:129:24:129:24 | n | provenance | |
| main.rs:129:9:129:26 | MyInt {...} [MyInt] | main.rs:128:28:130:5 | { ... } [MyInt] | provenance | |
| main.rs:129:24:129:24 | n | main.rs:129:9:129:26 | MyInt {...} [MyInt] | provenance | |
Expand Down Expand Up @@ -130,6 +139,15 @@ nodes
| main.rs:103:13:103:30 | mn.data_through(...) | semmle.label | mn.data_through(...) |
| main.rs:103:29:103:29 | a | semmle.label | a |
| main.rs:104:10:104:10 | b | semmle.label | b |
| main.rs:109:9:109:9 | a | semmle.label | a |
| main.rs:109:13:109:21 | source(...) | semmle.label | source(...) |
| main.rs:110:26:110:26 | a | semmle.label | a |
| main.rs:115:9:115:9 | a | semmle.label | a |
| main.rs:115:13:115:22 | source(...) | semmle.label | source(...) |
| main.rs:116:9:116:9 | b | semmle.label | b |
| main.rs:116:13:116:40 | ...::data_through(...) | semmle.label | ...::data_through(...) |
| main.rs:116:39:116:39 | a | semmle.label | a |
| main.rs:117:10:117:10 | b | semmle.label | b |
| main.rs:128:12:128:17 | ...: i64 | semmle.label | ...: i64 |
| main.rs:128:28:130:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] |
| main.rs:129:9:129:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] |
Expand Down Expand Up @@ -179,6 +197,7 @@ subpaths
| main.rs:41:26:44:5 | { ... } | main.rs:30:17:30:22 | ...: i64 | main.rs:30:32:32:1 | { ... } | main.rs:41:13:44:6 | pass_through(...) |
| main.rs:55:26:55:26 | a | main.rs:51:21:51:26 | ...: i64 | main.rs:51:36:53:5 | { ... } | main.rs:55:13:55:27 | pass_through(...) |
| main.rs:103:29:103:29 | a | main.rs:79:28:79:33 | ...: i64 | main.rs:79:43:85:5 | { ... } | main.rs:103:13:103:30 | mn.data_through(...) |
| main.rs:116:39:116:39 | a | main.rs:79:28:79:33 | ...: i64 | main.rs:79:43:85:5 | { ... } | main.rs:116:13:116:40 | ...::data_through(...) |
| main.rs:134:24:134:33 | source(...) | main.rs:128:12:128:17 | ...: i64 | main.rs:128:28:130:5 | { ... } [MyInt] | main.rs:134:13:134:34 | ...::new(...) [MyInt] |
| main.rs:187:49:187:49 | a [MyInt] | main.rs:175:18:175:21 | SelfParam [MyInt] | main.rs:175:48:177:5 | { ... } [MyInt] | main.rs:187:30:187:53 | ...::take_self(...) [MyInt] |
| main.rs:192:54:192:54 | b [MyInt] | main.rs:179:26:179:37 | ...: MyInt [MyInt] | main.rs:179:49:181:5 | { ... } [MyInt] | main.rs:192:30:192:55 | ...::take_second(...) [MyInt] |
Expand All @@ -191,8 +210,10 @@ testFailures
| main.rs:45:10:45:10 | a | main.rs:43:9:43:18 | source(...) | main.rs:45:10:45:10 | a | $@ | main.rs:43:9:43:18 | source(...) | source(...) |
| main.rs:56:10:56:10 | b | main.rs:49:13:49:22 | source(...) | main.rs:56:10:56:10 | b | $@ | main.rs:49:13:49:22 | source(...) | source(...) |
| main.rs:68:14:68:14 | n | main.rs:96:13:96:21 | source(...) | main.rs:68:14:68:14 | n | $@ | main.rs:96:13:96:21 | source(...) | source(...) |
| main.rs:68:14:68:14 | n | main.rs:109:13:109:21 | source(...) | main.rs:68:14:68:14 | n | $@ | main.rs:109:13:109:21 | source(...) | source(...) |
| main.rs:91:10:91:10 | a | main.rs:75:13:75:21 | source(...) | main.rs:91:10:91:10 | a | $@ | main.rs:75:13:75:21 | source(...) | source(...) |
| main.rs:104:10:104:10 | b | main.rs:102:13:102:21 | source(...) | main.rs:104:10:104:10 | b | $@ | main.rs:102:13:102:21 | source(...) | source(...) |
| main.rs:117:10:117:10 | b | main.rs:115:13:115:22 | source(...) | main.rs:117:10:117:10 | b | $@ | main.rs:115:13:115:22 | source(...) | source(...) |
| main.rs:136:10:136:10 | m | main.rs:134:24:134:33 | source(...) | main.rs:136:10:136:10 | m | $@ | main.rs:134:24:134:33 | source(...) | source(...) |
| main.rs:188:10:188:10 | c | main.rs:185:28:185:36 | source(...) | main.rs:188:10:188:10 | c | $@ | main.rs:185:28:185:36 | source(...) | source(...) |
| main.rs:193:10:193:10 | c | main.rs:191:28:191:37 | source(...) | main.rs:193:10:193:10 | c | $@ | main.rs:191:28:191:37 | source(...) | source(...) |
Expand Down
4 changes: 2 additions & 2 deletions rust/ql/test/library-tests/dataflow/global/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ struct MyFlag {

impl MyFlag {
fn data_in(&self, n: i64) {
sink(n); // $ hasValueFlow=1 MISSING: hasValueFlow=8
sink(n); // $ hasValueFlow=1 hasValueFlow=8
}

fn get_data(&self) -> i64 {
Expand Down Expand Up @@ -114,7 +114,7 @@ fn data_through_method_called_as_function() {
let mn = MyFlag { flag: true };
let a = source(12);
let b = MyFlag::data_through(&mn, a);
sink(b); // $ MISSING: hasValueFlow=12
sink(b); // $ hasValueFlow=12
}

use std::ops::Add;
Expand Down
149 changes: 147 additions & 2 deletions rust/ql/test/library-tests/path-resolution/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ mod m8 {
pub fn g() {
let x = MyStruct {}; // $ item=I50
MyTrait::f(&x); // $ item=I48
MyStruct::f(&x); // $ MISSING: item=I53
MyStruct::f(&x); // $ item=I53
<MyStruct as // $ item=I50
MyTrait // $ MISSING: item=I47
> // $ MISSING: item=52
Expand All @@ -187,7 +187,7 @@ mod m8 {
x.f(); // $ MISSING: item=I53
let x = MyStruct {}; // $ item=I50
x.g(); // $ MISSING: item=I54
MyStruct::h(&x); // $ MISSING: item=I74
MyStruct::h(&x); // $ item=I74
x.h(); // $ MISSING: item=I74
} // I55
} // I46
Expand Down Expand Up @@ -291,6 +291,149 @@ mod m13 {
}
}

mod m15 {
trait Trait1 {
fn f(&self);

fn g(&self); // I80
} // I79

#[rustfmt::skip]
trait Trait2
: Trait1 { // $ item=I79
fn f(&self) {
println!("m15::Trait2::f");
Self::g(self); // $ item=I80
self.g(); // $ MISSING: item=I80
}
} // I82

struct S; // I81

#[rustfmt::skip]
impl Trait1 // $ item=I79
for S { // $ item=I81
fn f(&self) {
println!("m15::<S as Trait1>::f");
Self::g(self); // $ item=I77
self.g(); // $ MISSING: item=I77
} // I76

fn g(&self) {
println!("m15::<S as Trait1>::g");
} // I77
}

#[rustfmt::skip]
impl Trait2 // $ item=I82
for S { // $ item=I81
fn f(&self) {
println!("m15::<S as Trait2>::f");
} // I78
}

#[rustfmt::skip]
pub fn f() {
println!("m15::f");
let x = S; // $ item=I81
<S // $ item=I81
as Trait1 // $ MISSING: item=I79
>::f(&x); // $ MISSING: item=I76
<S // $ item=I81
as Trait2 // MISSING: item=I82
>::f(&x); // $ MISSING: item=I78
S::g(&x); // $ item=I77
x.g(); // $ MISSING: item=I77
} // I75
}

mod m16 {
#[rustfmt::skip]
trait Trait1<
T // I84
> {
fn f(&self) -> T; // $ item=I84

fn g(&self) -> T // $ item=I84
; // I85

const c: T // $ item=I84
; // I94
} // I86

#[rustfmt::skip]
trait Trait2<
T // I87
> // I88
: Trait1<
T // $ item=I87
> { // $ item=I86
fn f(&self) -> T { // $ item=I87
println!("m16::Trait2::f");
Self::g(self); // $ item=I85
self.g(); // $ MISSING: item=I85
Self::c // $ item=I94
}
} // I89

struct S; // I90

#[rustfmt::skip]
impl Trait1<
S // $ item=I90
> // $ item=I86
for S { // $ item=I90
fn f(&self) -> S { // $ item=I90
println!("m16::<S as Trait1<S>>::f");
Self::g(self); // $ item=I92
self.g() // $ MISSING: item=I92
} // I91

fn g(&self) -> S { // $ item=I90
println!("m16::<S as Trait1<S>>::g");
Self::c // $ item=I95
} // I92

const c: S = S // $ item=I90
; // I95
}

#[rustfmt::skip]
impl Trait2<
S // $ item=I90
> // $ item=I89
for S { // $ item=I90
fn f(&self) -> S { // $ item=I90
println!("m16::<S as Trait2<S>>::f");
Self::c // $ MISSING: item=I95
} // I93
}

#[rustfmt::skip]
pub fn f() {
println!("m16::f");
let x = S; // $ item=I90
<S // $ item=I90
as Trait1<
S // $ item=I90
> // $ MISSING: item=I86
>::f(&x); // $ MISSING: item=I91
<S // $ item=I90
as Trait2<
S // $ item=I90
> // MISSING: item=I89
>::f(&x); // $ MISSING: item=I93
S::g(&x); // $ item=I92
x.g(); // $ MISSING: item=I92
S::c; // $ item=I95
<S // $ item=I90
as Trait1<
S // $ item=I90
> // $ MISSING: item=I86
>::c; // $ MISSING: item=I95
} // I83
}

fn main() {
my::nested::nested1::nested2::f(); // $ item=I4
my::f(); // $ item=I38
Expand All @@ -310,4 +453,6 @@ fn main() {
m8::g(); // $ item=I55
m9::f(); // $ item=I57
m11::f(); // $ item=I63
m15::f(); // $ item=I75
m16::f(); // $ item=I83
}
Loading