Merge pull request #21282 from hvitved/rust/path-resolution/type-inference-expectations

Rust: Distinguish path resolution expectations from type inference expectations
This commit is contained in:
Tom Hvitved
2026-02-11 11:00:28 +01:00
committed by GitHub
3 changed files with 55 additions and 37 deletions

View File

@@ -8,7 +8,7 @@ private import codeql.rust.internal.typeinference.TypeInference
private import utils.test.InlineExpectationsTest
private module ResolveTest implements TestSig {
string getARelevantTag() { result = "item" }
string getARelevantTag() { result = ["item", "target", "item_not_target"] }
private predicate itemAt(ItemNode i, string filepath, int line) {
i.getLocation().hasLocationInfo(filepath, _, _, line, _)
@@ -36,19 +36,37 @@ private module ResolveTest implements TestSig {
)
}
private Item getCallExprTarget(Path p) {
exists(CallExpr ce |
p = ce.getFunction().(PathExpr).getPath() and
result = ce.getResolvedTarget()
)
}
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(AstNode n |
exists(AstNode n, ItemNode i |
not n = any(Path parent).getQualifier() and
location = n.getLocation() and
n.fromSource() and
not location.getFile().getAbsolutePath().matches("%proc_macro.rs") and
not n.isFromMacroExpansion() and
element = n.toString() and
tag = "item"
item(i, value)
|
item(resolvePath(n), value)
i = resolvePath(n) and
(
if exists(getCallExprTarget(n)) and not i = getCallExprTarget(n)
then tag = "item_not_target"
else tag = "item"
)
or
item(n.(MethodCallExpr).getStaticTarget(), value)
tag = "target" and
(
i = n.(MethodCallExpr).getStaticTarget()
or
i = getCallExprTarget(n) and
not i = resolvePath(n)
)
)
}
}

View File

@@ -189,18 +189,18 @@ mod m8 {
#[rustfmt::skip]
pub fn g() {
let x = MyStruct {}; // $ item=I50
MyTrait::f(&x); // $ item=I48
MyTrait::f(&x); // $ item_not_target=I48 target=I53
MyStruct::f(&x); // $ item=I53
<MyStruct as // $ item=I50
MyTrait // $ item=I47
> // $ MISSING: item=52
::f(&x); // $ item=I48
::f(&x); // $ item_not_target=I48 target=I53
let x = MyStruct {}; // $ item=I50
x.f(); // $ item=I53
x.f(); // $ target=I53
let x = MyStruct {}; // $ item=I50
x.g(); // $ item=I54
x.g(); // $ target=I54
MyStruct::h(&x); // $ item=I74
x.h(); // $ item=I74
x.h(); // $ target=I74
} // I55
} // I46
@@ -316,7 +316,7 @@ mod m15 {
fn f(&self) {
println!("m15::Trait2::f"); // $ item=println
Self::g(self); // $ item=I80
self.g(); // $ item=I80
self.g(); // $ target=I80
} // Trait2::f
} // I82
@@ -331,7 +331,7 @@ mod m15 {
fn f(&self, tt: TT) { // $ item=ITT
Self::g(self); // $ item=I80
TT::g(&tt); // $ item=I80
self.g(); // $ item=I80
self.g(); // $ target=I80
}
} // ITrait3
@@ -343,7 +343,7 @@ mod m15 {
fn f(&self) {
println!("m15::<S as Trait1>::f"); // $ item=println
Self::g(self); // $ item=I77
self.g(); // $ item=I77
self.g(); // $ target=I77
} // I76
fn g(&self) {
@@ -365,12 +365,12 @@ mod m15 {
let x = S; // $ item=I81
<S // $ item=I81
as Trait1 // $ item=I79
>::f(&x); // $ item=Trait1::f
>::f(&x); // $ item_not_target=Trait1::f target=I76
<S // $ item=I81
as Trait2 // $ item=I82
>::f(&x); // $ item=Trait2::f
>::f(&x); // $ item_not_target=Trait2::f target=I78
S::g(&x); // $ item=I77
x.g(); // $ item=I77
x.g(); // $ target=I77
} // I75
}
@@ -383,12 +383,12 @@ mod m16 {
; // Trait1::f
fn g(&self) -> T {// $ item=I84
self.f() // $ item=Trait1::f
self.f() // $ target=Trait1::f
} // I85
fn h(&self) -> T { // $ item=I84
Self::g(&self); // $ item=I85
self.g() // $ item=I85
self.g() // $ target=I85
} // I96
const c: T // $ item=I84
@@ -405,7 +405,7 @@ mod m16 {
fn f(&self) -> T { // $ item=I87
println!("m16::Trait2::f"); // $ item=println
Self::g(self); // $ item=I85
self.g(); // $ item=I85
self.g(); // $ target=I85
Self::c // $ item=I94
} // Trait2::f
} // I89
@@ -420,7 +420,7 @@ mod m16 {
fn f(&self) -> S { // $ item=I90
println!("m16::<S as Trait1<S>>::f"); // $ item=println
Self::g(self); // $ item=I92
self.g() // $ item=I92
self.g() // $ target=I92
} // I91
fn g(&self) -> S { // $ item=I90
@@ -452,16 +452,16 @@ mod m16 {
as Trait1<
S // $ item=I90
> // $ item=I86
>::f(&x); // $ item=Trait1::f
>::f(&x); // $ item_not_target=Trait1::f target=I91
<S // $ item=I90
as Trait2<
S // $ item=I90
> // $ item=I89
>::f(&x); // $ item=Trait2::f
>::f(&x); // $ item_not_target=Trait2::f target=I93
S::g(&x); // $ item=I92
x.g(); // $ item=I92
x.g(); // $ target=I92
S::h(&x); // $ item=I96
x.h(); // $ item=I96
x.h(); // $ target=I96
S::c; // $ item=I95
<S // $ item=I90
as Trait1<
@@ -564,13 +564,13 @@ mod m16 {
#[rustfmt::skip]
fn foo() {
S3::<i32>:: // $ item=i32
Assoc(); // $ item=S3i32AssocFunc $ SPURIOUS: item=S3boolAssocFunc (the spurious target is later filtered away by type inference)
Assoc(); // $ item=S3i32AssocFunc item_not_target=S3boolAssocFunc
S3::<bool>:: // $ item=bool
f1(); // $ item=S3boolf1 $ SPURIOUS: item=S3i32f1 (the spurious target is later filtered away by type inference)
f1(); // $ item=S3boolf1 item_not_target=S3i32f1
S3::<i32>:: // $ item=i32
f1(); // $ item=S3i32f1 $ SPURIOUS: item=S3boolf1 (the spurious target is later filtered away by type inference)
f1(); // $ item=S3i32f1 item_not_target=S3boolf1
}
}
@@ -628,7 +628,7 @@ mod trait_visibility {
{
// The `Bar` trait is not visible, but we can refer to its method
// with a full path.
m::Bar::a_method(&x); // $ item=Bar::a_method
m::Bar::a_method(&x); // $ item_not_target=Bar::a_method target=X_Bar::a_method
}
} // trait_visibility::f
}
@@ -652,7 +652,7 @@ mod m17 {
fn g<T: // I5
MyTrait // $ item=I2
>(x: T) { // $ item=I5
x.f(); // $ item=I1
x.f(); // $ target=I1
T::f(&x); // $ item=I1
MyTrait::f(&x); // $ item=I1
} // I6
@@ -735,7 +735,7 @@ mod m23 {
#[rustfmt::skip]
pub fn f() {
let x = S; // $ item=I4
x.f(); // $ item=I5
x.f(); // $ target=I5
} // I108
}
@@ -760,7 +760,7 @@ mod m24 {
T: TraitA // $ item=I111 item=I1151
{
fn call_trait_a(&self) {
self.data.trait_a_method(); // $ item=I110
self.data.trait_a_method(); // $ target=I110
} // I116
}
@@ -772,8 +772,8 @@ mod m24 {
T: TraitA, // $ item=I111 item=I1161
{
fn call_both(&self) {
self.data.trait_a_method(); // $ item=I110
self.data.trait_b_method(); // $ item=I112
self.data.trait_a_method(); // $ target=I110
self.data.trait_b_method(); // $ target=I112
} // I117
}
@@ -798,8 +798,8 @@ mod m24 {
let impl_obj = Implementor; // $ item=I118
let generic = GenericStruct { data: impl_obj }; // $ item=I115
generic.call_trait_a(); // $ item=I116
generic.call_both(); // $ item=I117
generic.call_trait_a(); // $ target=I116
generic.call_both(); // $ target=I117
// Access through where clause type parameter constraint
GenericStruct::<Implementor>::call_trait_a(&generic); // $ item=I116 item=I118
@@ -1132,7 +1132,7 @@ fn main() {
zelf::h(); // $ item=I25
z_changed(); // $ item=I122
AStruct::z_on_type(); // $ item=I124
AStruct {}.z_on_instance(); // $ item=I123 item=I125
AStruct {}.z_on_instance(); // $ item=I123 target=I125
impl_with_attribute_macro::test(); // $ item=impl_with_attribute_macro::test
patterns::test(); // $ item=patterns::test
}

View File

@@ -30,7 +30,7 @@ fn int_div(
) -> Result<i32> // $ item=my::Result $ item=i32
{
if y == 0 {
return Err("Div by zero".to_string()); // $ item=Err item=to_string
return Err("Div by zero".to_string()); // $ item=Err target=to_string
}
Ok(x / y) // $ item=Ok
}