Merge pull request #19993 from hvitved/rust/type-inference-function-call-expectations

Rust: Add type inference inline expectations for all function calls
This commit is contained in:
Tom Hvitved
2025-07-07 20:40:57 +02:00
committed by GitHub
6 changed files with 2695 additions and 2680 deletions

View File

@@ -15,3 +15,6 @@ import codeql.rust.elements.AsyncBlockExpr
import codeql.rust.elements.Variable import codeql.rust.elements.Variable
import codeql.rust.elements.NamedFormatArgument import codeql.rust.elements.NamedFormatArgument
import codeql.rust.elements.PositionalFormatArgument import codeql.rust.elements.PositionalFormatArgument
private import codeql.rust.elements.Call as Call
class Call = Call::Call;

View File

@@ -1,9 +1,9 @@
multipleCallTargets multipleCallTargets
| dereference.rs:61:15:61:24 | e1.deref() | | dereference.rs:61:15:61:24 | e1.deref() |
| main.rs:2086:13:2086:31 | ...::from(...) |
| main.rs:2087:13:2087:31 | ...::from(...) |
| main.rs:2088:13:2088:31 | ...::from(...) |
| main.rs:2094:13:2094:31 | ...::from(...) |
| main.rs:2095:13:2095:31 | ...::from(...) |
| main.rs:2096:13:2096:31 | ...::from(...) | | main.rs:2096:13:2096:31 | ...::from(...) |
| main.rs:2132:21:2132:43 | ...::from(...) | | main.rs:2097:13:2097:31 | ...::from(...) |
| main.rs:2098:13:2098:31 | ...::from(...) |
| main.rs:2104:13:2104:31 | ...::from(...) |
| main.rs:2105:13:2105:31 | ...::from(...) |
| main.rs:2106:13:2106:31 | ...::from(...) |
| main.rs:2142:21:2142:43 | ...::from(...) |

View File

@@ -71,15 +71,15 @@ fn explicit_ref_dereference() {
fn explicit_box_dereference() { fn explicit_box_dereference() {
// Explicit dereference with type parameter // Explicit dereference with type parameter
let g1: Box<char> = Box::new('a'); let g1: Box<char> = Box::new('a'); // $ method=new
let _h1 = g1.deref(); // $ method=deref type=_h1:&T.char let _h1 = g1.deref(); // $ method=deref type=_h1:&T.char
// Explicit dereference with type parameter // Explicit dereference with type parameter
let g2: Box<char> = Box::new('a'); let g2: Box<char> = Box::new('a'); // $ method=new
let _h2 = *g2; // $ method=deref type=_h2:char let _h2 = *g2; // $ method=deref type=_h2:char
// Call method on explicitly dereferenced value with type parameter // Call method on explicitly dereferenced value with type parameter
let g3: Box<i64> = Box::new(34i64); let g3: Box<i64> = Box::new(34i64); // $ method=new
let _h3 = (*g3).is_positive(); // $ method=deref method=is_positive type=_h3:bool let _h3 = (*g3).is_positive(); // $ method=deref method=is_positive type=_h3:bool
} }
@@ -94,9 +94,9 @@ fn implicit_dereference() {
} }
pub fn test() { pub fn test() {
explicit_monomorphic_dereference(); explicit_monomorphic_dereference(); // $ method=explicit_monomorphic_dereference
explicit_polymorphic_dereference(); explicit_polymorphic_dereference(); // $ method=explicit_polymorphic_dereference
explicit_ref_dereference(); explicit_ref_dereference(); // $ method=explicit_ref_dereference
explicit_box_dereference(); explicit_box_dereference(); // $ method=explicit_box_dereference
implicit_dereference(); implicit_dereference(); // $ method=implicit_dereference
} }

View File

@@ -63,8 +63,8 @@ mod field_access {
} }
pub fn f() { pub fn f() {
simple_field_access(); simple_field_access(); // $ method=simple_field_access
generic_field_access(); generic_field_access(); // $ method=generic_field_access
} }
} }
@@ -234,7 +234,7 @@ mod method_non_parametric_trait_impl {
{ {
// MyThing<S3>::m1 // MyThing<S3>::m1
fn m1(self) -> TD { fn m1(self) -> TD {
TD::default() TD::default() // $ method=default
} }
} }
@@ -362,34 +362,34 @@ mod method_non_parametric_trait_impl {
// Tests for inference of type parameters based on trait implementations. // Tests for inference of type parameters based on trait implementations.
let x = call_trait_m1(thing_s1); // $ type=x:S1 let x = call_trait_m1(thing_s1); // $ type=x:S1 method=call_trait_m1
println!("{:?}", x); println!("{:?}", x);
let y = call_trait_m1(thing_s2); // $ type=y:MyThing type=y:A.S2 let y = call_trait_m1(thing_s2); // $ type=y:MyThing type=y:A.S2 method=call_trait_m1
println!("{:?}", y.a); // $ fieldof=MyThing println!("{:?}", y.a); // $ fieldof=MyThing
// First implementation // First implementation
let a = MyPair { p1: S1, p2: S1 }; let a = MyPair { p1: S1, p2: S1 };
let x = get_fst(a); // $ type=x:S1 let x = get_fst(a); // $ type=x:S1 method=get_fst
println!("{:?}", x); println!("{:?}", x);
let y = get_snd(a); // $ type=y:S1 let y = get_snd(a); // $ type=y:S1 method=get_snd
println!("{:?}", y); println!("{:?}", y);
// Second implementation // Second implementation
let b = MyPair { p1: S2, p2: S1 }; let b = MyPair { p1: S2, p2: S1 };
let x = get_fst(b); // $ type=x:S1 let x = get_fst(b); // $ type=x:S1 method=get_fst
println!("{:?}", x); println!("{:?}", x);
let y = get_snd(b); // $ type=y:S2 let y = get_snd(b); // $ type=y:S2 method=get_snd
println!("{:?}", y); println!("{:?}", y);
let c = MyPair { let c = MyPair {
p1: S3, p1: S3,
p2: MyPair { p1: S2, p2: S1 }, p2: MyPair { p1: S2, p2: S1 },
}; };
let x = get_snd_fst(c); // $ type=x:S1 let x = get_snd_fst(c); // $ type=x:S1 method=get_snd_fst
let thing = MyThing { a: S1 }; let thing = MyThing { a: S1 };
let i = thing.convert_to(); // $ MISSING: type=i:S1 method=T::convert_to let i = thing.convert_to(); // $ MISSING: type=i:S1 method=T::convert_to
let j = convert_to(thing); // $ type=j:S1 let j = convert_to(thing); // $ type=j:S1 method=convert_to
} }
} }
@@ -603,11 +603,13 @@ mod function_trait_bounds {
} }
// Type parameter with bound occurs in the root of a parameter type. // Type parameter with bound occurs in the root of a parameter type.
fn call_trait_m1<T1, T2: MyTrait<T1>>(x: T2) -> T1 { fn call_trait_m1<T1, T2: MyTrait<T1>>(x: T2) -> T1 {
x.m1() // $ method=m1 type=x.m1():T1 x.m1() // $ method=m1 type=x.m1():T1
} }
// Type parameter with bound occurs nested within another type. // Type parameter with bound occurs nested within another type.
fn call_trait_thing_m1<T1, T2: MyTrait<T1>>(x: MyThing<T2>) -> T1 { fn call_trait_thing_m1<T1, T2: MyTrait<T1>>(x: MyThing<T2>) -> T1 {
x.a.m1() // $ fieldof=MyThing method=m1 x.a.m1() // $ fieldof=MyThing method=m1
} }
@@ -634,8 +636,8 @@ mod function_trait_bounds {
let x2 = MyThing { a: S1 }; let x2 = MyThing { a: S1 };
let y2 = MyThing { a: S2 }; let y2 = MyThing { a: S2 };
println!("{:?}", call_trait_m1(x2)); println!("{:?}", call_trait_m1(x2)); // $ method=call_trait_m1
println!("{:?}", call_trait_m1(y2)); println!("{:?}", call_trait_m1(y2)); // $ method=call_trait_m1
let x3 = MyThing { let x3 = MyThing {
a: MyThing { a: S1 }, a: MyThing { a: S1 },
@@ -644,9 +646,9 @@ mod function_trait_bounds {
a: MyThing { a: S2 }, a: MyThing { a: S2 },
}; };
let a = call_trait_thing_m1(x3); // $ type=a:S1 let a = call_trait_thing_m1(x3); // $ type=a:S1 method=call_trait_thing_m1
println!("{:?}", a); println!("{:?}", a);
let b = call_trait_thing_m1(y3); // $ type=b:S2 let b = call_trait_thing_m1(y3); // $ type=b:S2 method=call_trait_thing_m1
println!("{:?}", b); println!("{:?}", b);
} }
} }
@@ -748,6 +750,7 @@ mod trait_associated_type {
} }
// Function that returns an associated type from a trait bound // Function that returns an associated type from a trait bound
fn g<T: MyTrait>(thing: T) -> <T as MyTrait>::AssociatedType { fn g<T: MyTrait>(thing: T) -> <T as MyTrait>::AssociatedType {
thing.m1() // $ method=MyTrait::m1 thing.m1() // $ method=MyTrait::m1
} }
@@ -786,7 +789,7 @@ mod trait_associated_type {
// Call to default implementation in `trait` block // Call to default implementation in `trait` block
println!("{:?}", x3.putTwo(2, 3).unwrap()); // $ method=putTwo method=unwrap println!("{:?}", x3.putTwo(2, 3).unwrap()); // $ method=putTwo method=unwrap
let x4 = g(S); // $ MISSING: type=x4:AT let x4 = g(S); // $ method=g $ MISSING: type=x4:AT
println!("{:?}", x4); println!("{:?}", x4);
let x5 = S2; let x5 = S2;
@@ -929,10 +932,10 @@ mod method_supertraits {
println!("{:?}", y.m3()); // $ method=m3 type=y.m3():S2 println!("{:?}", y.m3()); // $ method=m3 type=y.m3():S2
let x = MyThing { a: S1 }; let x = MyThing { a: S1 };
let s = call_trait_m1(x); // $ type=s:S1 let s = call_trait_m1(x); // $ type=s:S1 method=call_trait_m1
let x = MyThing2 { a: S2 }; let x = MyThing2 { a: S2 };
let s = call_trait_m1(x); // $ type=s:MyThing type=s:A.S2 let s = call_trait_m1(x); // $ type=s:MyThing type=s:A.S2 method=call_trait_m1
} }
} }
@@ -968,19 +971,20 @@ mod function_trait_bounds_2 {
pub fn f() { pub fn f() {
let x = S1; let x = S1;
println!("{:?}", id(&x)); println!("{:?}", id(&x)); // $ method=id
let x = S1; let x = S1;
println!("{:?}", id::<S1>(&x)); println!("{:?}", id::<S1>(&x)); // $ method=id
let x = S1; let x = S1;
println!("{:?}", id::<dyn Trait>(&x)); // incorrectly has type `S1` instead of `Trait` // incorrectly has type `S1` instead of `Trait`
println!("{:?}", id::<dyn Trait>(&x)); // $ method=id
let x = S1; let x = S1;
into::<S1, S2>(x); into::<S1, S2>(x); // $ method=into
let x = S1; let x = S1;
let y: S2 = into(x); let y: S2 = into(x); // $ method=into
} }
} }
@@ -1055,7 +1059,7 @@ mod type_aliases {
let p3: AnotherPair<S3> = PairOption::PairNone(); // $ type=p3:Fst.S2 type=p3:Snd.S3 let p3: AnotherPair<S3> = PairOption::PairNone(); // $ type=p3:Fst.S2 type=p3:Snd.S3
println!("{:?}", p3); println!("{:?}", p3);
g(PairOption::PairSnd(PairOption::PairSnd(S3))); g(PairOption::PairSnd(PairOption::PairSnd(S3))); // $ method=g
let x: S7<S2>; // $ type=x:Result $ type=x:E.S1 $ type=x:T.S4 $ type=x:T.T41.S2 $ type=x:T.T42.S5 $ type=x:T.T42.T5.S2 let x: S7<S2>; // $ type=x:Result $ type=x:E.S1 $ type=x:T.S4 $ type=x:T.T41.S2 $ type=x:T.T42.S5 $ type=x:T.T42.T5.S2
} }
@@ -1101,19 +1105,20 @@ mod option_methods {
struct S; struct S;
pub fn f() { pub fn f() {
let x1 = MyOption::<S>::new(); // $ type=x1:T.S let x1 = MyOption::<S>::new(); // $ type=x1:T.S method=new
println!("{:?}", x1); println!("{:?}", x1);
let mut x2 = MyOption::new(); let mut x2 = MyOption::new(); // $ method=new
x2.set(S); // $ method=MyOption::set x2.set(S); // $ method=MyOption::set
println!("{:?}", x2); println!("{:?}", x2);
let mut x3 = MyOption::new(); // missing type `S` from `MyOption<S>` (but can resolve `MyTrait<S>`) // missing type `S` from `MyOption<S>` (but can resolve `MyTrait<S>`)
let mut x3 = MyOption::new(); // $ method=new
x3.call_set(S); // $ method=call_set x3.call_set(S); // $ method=call_set
println!("{:?}", x3); println!("{:?}", x3);
let mut x4 = MyOption::new(); let mut x4 = MyOption::new(); // $ method=new
MyOption::set(&mut x4, S); MyOption::set(&mut x4, S); // $ method=MyOption::set
println!("{:?}", x4); println!("{:?}", x4);
let x5 = MyOption::MySome(MyOption::<S>::MyNone()); let x5 = MyOption::MySome(MyOption::<S>::MyNone());
@@ -1204,8 +1209,8 @@ mod method_call_type_conversion {
let x3 = S(S2); let x3 = S(S2);
// explicit borrow // explicit borrow
println!("{:?}", S::<S2>::m2(&x3)); println!("{:?}", S::<S2>::m2(&x3)); // $ method=m2
println!("{:?}", S::<S2>::m3(&x3)); println!("{:?}", S::<S2>::m3(&x3)); // $ method=m3
let x4 = &S(S2); let x4 = &S(S2);
// explicit borrow // explicit borrow
@@ -1325,14 +1330,14 @@ mod borrowed_typed {
let x = S {}; let x = S {};
x.f1(); // $ method=f1 x.f1(); // $ method=f1
x.f2(); // $ method=f2 x.f2(); // $ method=f2
S::f3(&x); S::f3(&x); // $ method=f3
let n = **&&true; // $ type=n:bool method=deref let n = **&&true; // $ type=n:bool method=deref
// In this example the type of `flag` must be inferred at the call to // In this example the type of `flag` must be inferred at the call to
// `flip` and flow through the borrow in the argument. // `flip` and flow through the borrow in the argument.
let mut flag = Default::default(); let mut flag = Default::default(); // $ method=default
MyFlag::flip(&mut flag); MyFlag::flip(&mut flag); // $ method=flip
println!("{:?}", flag); // $ type=flag:MyFlag println!("{:?}", flag); // $ type=flag:MyFlag
} }
} }
@@ -1347,12 +1352,14 @@ mod try_expressions {
struct S2; struct S2;
// Simple function using ? operator with same error types // Simple function using ? operator with same error types
fn try_same_error() -> Result<S1, S1> { fn try_same_error() -> Result<S1, S1> {
let x = Result::Ok(S1)?; // $ type=x:S1 let x = Result::Ok(S1)?; // $ type=x:S1
Result::Ok(S1) Result::Ok(S1)
} }
// Function using ? operator with different error types that need conversion // Function using ? operator with different error types that need conversion
fn try_convert_error() -> Result<S1, S2> { fn try_convert_error() -> Result<S1, S2> {
let x = Result::Ok(S1); let x = Result::Ok(S1);
let y = x?; // $ type=y:S1 let y = x?; // $ type=y:S1
@@ -1360,6 +1367,7 @@ mod try_expressions {
} }
// Chained ? operations // Chained ? operations
fn try_chained() -> Result<S1, S2> { fn try_chained() -> Result<S1, S2> {
let x = Result::Ok(Result::Ok(S1)); let x = Result::Ok(Result::Ok(S1));
// First ? returns Result<S1, S2>, second ? returns S1 // First ? returns Result<S1, S2>, second ? returns S1
@@ -1368,6 +1376,7 @@ mod try_expressions {
} }
// Function that uses ? with closures and complex error cases // Function that uses ? with closures and complex error cases
fn try_complex<T: Debug>(input: Result<T, S1>) -> Result<T, S1> { fn try_complex<T: Debug>(input: Result<T, S1>) -> Result<T, S1> {
let value = input?; let value = input?;
let mapped = Result::Ok(value).and_then(|v| { let mapped = Result::Ok(value).and_then(|v| {
@@ -1377,20 +1386,21 @@ mod try_expressions {
Result::Err(S1) Result::Err(S1)
} }
#[rustfmt::skip]
pub fn f() { pub fn f() {
if let Result::Ok(result) = try_same_error() { if let Result::Ok(result) = try_same_error() { // $ method=try_same_error
println!("{:?}", result); println!("{:?}", result);
} }
if let Result::Ok(result) = try_convert_error() { if let Result::Ok(result) = try_convert_error() { // $ method=try_convert_error
println!("{:?}", result); println!("{:?}", result);
} }
if let Result::Ok(result) = try_chained() { if let Result::Ok(result) = try_chained() { // $ method=try_chained
println!("{:?}", result); println!("{:?}", result);
} }
if let Result::Ok(result) = try_complex(Result::Ok(S1)) { if let Result::Ok(result) = try_complex(Result::Ok(S1)) { // $ method=try_complex
println!("{:?}", result); println!("{:?}", result);
} }
} }
@@ -1789,12 +1799,12 @@ mod overloadable_operators {
let vec2_not = !v1; // $ type=vec2_not:Vec2 method=Vec2::not let vec2_not = !v1; // $ type=vec2_not:Vec2 method=Vec2::not
// Here the type of `default_vec2` must be inferred from the `+` call. // Here the type of `default_vec2` must be inferred from the `+` call.
let default_vec2 = Default::default(); // $ type=default_vec2:Vec2 let default_vec2 = Default::default(); // $ type=default_vec2:Vec2 method=default
let vec2_zero_plus = Vec2 { x: 0, y: 0 } + default_vec2; // $ method=Vec2::add let vec2_zero_plus = Vec2 { x: 0, y: 0 } + default_vec2; // $ method=Vec2::add
// Here the type of `default_vec2` must be inferred from the `==` call // Here the type of `default_vec2` must be inferred from the `==` call
// and the type of the borrowed second argument is unknown at the call. // and the type of the borrowed second argument is unknown at the call.
let default_vec2 = Default::default(); // $ type=default_vec2:Vec2 let default_vec2 = Default::default(); // $ type=default_vec2:Vec2 method=default
let vec2_zero_plus = Vec2 { x: 0, y: 0 } == default_vec2; // $ method=Vec2::eq let vec2_zero_plus = Vec2 { x: 0, y: 0 } == default_vec2; // $ method=Vec2::eq
} }
} }
@@ -1834,9 +1844,9 @@ mod async_ {
} }
pub async fn f() { pub async fn f() {
f1().await.f(); // $ method=S1f f1().await.f(); // $ method=S1f method=f1
f2().await.f(); // $ method=S1f f2().await.f(); // $ method=S1f method=f2
f3().await.f(); // $ method=S1f f3().await.f(); // $ method=S1f method=f3
S2.await.f(); // $ method=S1f S2.await.f(); // $ method=S1f
let b = async { S1 }; let b = async { S1 };
b.await.f(); // $ method=S1f b.await.f(); // $ method=S1f
@@ -1890,14 +1900,14 @@ mod impl_trait {
} }
pub fn f() { pub fn f() {
let x = f1(); let x = f1(); // $ method=f1
x.f1(); // $ method=Trait1f1 x.f1(); // $ method=Trait1f1
x.f2(); // $ method=Trait2f2 x.f2(); // $ method=Trait2f2
let a = get_a_my_trait(); let a = get_a_my_trait(); // $ method=get_a_my_trait
let b = uses_my_trait1(a); // $ type=b:S2 let b = uses_my_trait1(a); // $ type=b:S2 method=uses_my_trait1
let a = get_a_my_trait(); let a = get_a_my_trait(); // $ method=get_a_my_trait
let c = uses_my_trait2(a); // $ type=c:S2 let c = uses_my_trait2(a); // $ type=c:S2 method=uses_my_trait2
let d = uses_my_trait2(S1); // $ type=d:S2 let d = uses_my_trait2(S1); // $ type=d:S2 method=uses_my_trait2
} }
} }
@@ -1920,7 +1930,7 @@ mod indexers {
impl<T> MyVec<T> { impl<T> MyVec<T> {
fn new() -> Self { fn new() -> Self {
MyVec { data: Vec::new() } MyVec { data: Vec::new() } // $ method=new
} }
fn push(&mut self, value: T) { fn push(&mut self, value: T) {
@@ -1948,14 +1958,14 @@ mod indexers {
} }
pub fn f() { pub fn f() {
let mut vec = MyVec::new(); // $ type=vec:T.S let mut vec = MyVec::new(); // $ type=vec:T.S method=new
vec.push(S); // $ method=push vec.push(S); // $ method=push
vec[0].foo(); // $ method=MyVec::index method=foo vec[0].foo(); // $ method=MyVec::index method=foo
let xs: [S; 1] = [S]; let xs: [S; 1] = [S];
let x = xs[0].foo(); // $ method=foo type=x:S method=index let x = xs[0].foo(); // $ method=foo type=x:S method=index
analyze_slice(&xs); analyze_slice(&xs); // $ method=analyze_slice
} }
} }
@@ -2083,21 +2093,21 @@ mod loops {
let strings2 = // $ type=strings2:[T;...].String let strings2 = // $ type=strings2:[T;...].String
[ [
String::from("foo"), String::from("foo"), // $ method=from
String::from("bar"), String::from("bar"), // $ method=from
String::from("baz"), String::from("baz"), // $ method=from
]; ];
for s in strings2 {} // $ type=s:String for s in strings2 {} // $ type=s:String
let strings3 = // $ type=strings3:&T.[T;...].String let strings3 = // $ type=strings3:&T.[T;...].String
&[ &[
String::from("foo"), String::from("foo"), // $ method=from
String::from("bar"), String::from("bar"), // $ method=from
String::from("baz"), String::from("baz"), // $ method=from
]; ];
for s in strings3 {} // $ MISSING: type=s:String for s in strings3 {} // $ MISSING: type=s:String
let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ MISSING: type=callables:[T;...].MyCallable; 3 let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ method=new $ MISSING: type=callables:[T;...].MyCallable; 3
for c // $ type=c:MyCallable for c // $ type=c:MyCallable
in callables in callables
{ {
@@ -2129,13 +2139,13 @@ mod loops {
let vals4b = [1u16, 2, 3].to_vec(); // $ MISSING: type=vals4b:Vec type=vals4b:T.u16 let vals4b = [1u16, 2, 3].to_vec(); // $ MISSING: type=vals4b:Vec type=vals4b:T.u16
for u in vals4b {} // $ MISSING: type=u:u16 for u in vals4b {} // $ MISSING: type=u:u16
let vals5 = Vec::from([1u32, 2, 3]); // $ type=vals5:Vec MISSING: type=vals5:T.u32 let vals5 = Vec::from([1u32, 2, 3]); // $ type=vals5:Vec method=from MISSING: type=vals5:T.u32
for u in vals5 {} // $ MISSING: type=u:u32 for u in vals5 {} // $ MISSING: type=u:u32
let vals6: Vec<&u64> = [1u64, 2, 3].iter().collect(); // $ type=vals6:Vec type=vals6:T.&T.u64 let vals6: Vec<&u64> = [1u64, 2, 3].iter().collect(); // $ type=vals6:Vec type=vals6:T.&T.u64
for u in vals6 {} // $ type=u:&T.u64 for u in vals6 {} // $ type=u:&T.u64
let mut vals7 = Vec::new(); // $ type=vals7:Vec MISSING: type=vals7:T.u8 let mut vals7 = Vec::new(); // $ method=new type=vals7:Vec MISSING: type=vals7:T.u8
vals7.push(1u8); // $ method=push vals7.push(1u8); // $ method=push
for u in vals7 {} // $ MISSING: type=u:u8 for u in vals7 {} // $ MISSING: type=u:u8
@@ -2146,9 +2156,9 @@ mod loops {
} }
} }
let mut map1 = std::collections::HashMap::new(); // $ MISSING: type=map1:Hashmap type=map1:K.i32 type=map1:V.Box type1=map1:V.T.&T.str let mut map1 = std::collections::HashMap::new(); // $ method=new $ MISSING: type=map1:Hashmap type=map1:K.i32 type=map1:V.Box type1=map1:V.T.&T.str
map1.insert(1, Box::new("one")); // $ method=insert map1.insert(1, Box::new("one")); // $ method=insert method=new
map1.insert(2, Box::new("two")); // $ method=insert map1.insert(2, Box::new("two")); // $ method=insert method=new
for key in map1.keys() {} // $ method=keys MISSING: type=key:i32 for key in map1.keys() {} // $ method=keys MISSING: type=key:i32
for value in map1.values() {} // $ method=values MISSING: type=value:Box type=value:T.&T.str for value in map1.values() {} // $ method=values MISSING: type=value:Box type=value:T.&T.str
for (key, value) in map1.iter() {} // $ method=iter MISSING: type=key:i32 type=value:Box type=value:T.&T.str for (key, value) in map1.iter() {} // $ method=iter MISSING: type=key:i32 type=value:Box type=value:T.&T.str
@@ -2179,7 +2189,7 @@ mod explicit_type_args {
} }
fn default() -> Self { fn default() -> Self {
S1(T::default()) S1(T::default()) // $ method=default
} }
fn method(self) -> Self { fn method(self) -> Self {
@@ -2196,52 +2206,52 @@ mod explicit_type_args {
} }
pub fn f() { pub fn f() {
let x1: Option<S1<S2>> = S1::assoc_fun(); // $ type=x1:T.T.S2 let x1: Option<S1<S2>> = S1::assoc_fun(); // $ type=x1:T.T.S2 method=assoc_fun
let x2 = S1::<S2>::assoc_fun(); // $ type=x2:T.T.S2 let x2 = S1::<S2>::assoc_fun(); // $ type=x2:T.T.S2 method=assoc_fun
let x3 = S3::assoc_fun(); // $ type=x3:T.T.S2 let x3 = S3::assoc_fun(); // $ type=x3:T.T.S2 method=assoc_fun
let x4 = S1::<S2>::method(S1::default()); // $ method=method type=x4:T.S2 let x4 = S1::<S2>::method(S1::default()); // $ method=method method=default type=x4:T.S2
let x5 = S3::method(S1::default()); // $ method=method type=x5:T.S2 let x5 = S3::method(S1::default()); // $ method=method method=default type=x5:T.S2
let x6 = S4::<S2>(Default::default()); // $ type=x6:T4.S2 let x6 = S4::<S2>(Default::default()); // $ type=x6:T4.S2 method=default
let x7 = S4(S2); // $ type=x7:T4.S2 let x7 = S4(S2); // $ type=x7:T4.S2
let x8 = S4(0); // $ type=x8:T4.i32 let x8 = S4(0); // $ type=x8:T4.i32
let x9 = S4(S2::default()); // $ type=x9:T4.S2 let x9 = S4(S2::default()); // $ type=x9:T4.S2 method=default
let x10 = S5::<S2> // $ type=x10:T5.S2 let x10 = S5::<S2> // $ type=x10:T5.S2
{ {
field: Default::default(), field: Default::default(), // $ method=default
}; };
let x11 = S5 { field: S2 }; // $ type=x11:T5.S2 let x11 = S5 { field: S2 }; // $ type=x11:T5.S2
let x12 = S5 { field: 0 }; // $ type=x12:T5.i32 let x12 = S5 { field: 0 }; // $ type=x12:T5.i32
let x13 = S5 // $ type=x13:T5.S2 let x13 = S5 // $ type=x13:T5.S2
{ {
field: S2::default(), field: S2::default(), // $ method=default
}; };
} }
} }
fn main() { fn main() {
field_access::f(); field_access::f(); // $ method=f
method_impl::f(); method_impl::f(); // $ method=f
method_impl::g(method_impl::Foo {}, method_impl::Foo {}); method_impl::g(method_impl::Foo {}, method_impl::Foo {}); // $ method=g
method_non_parametric_impl::f(); method_non_parametric_impl::f(); // $ method=f
method_non_parametric_trait_impl::f(); method_non_parametric_trait_impl::f(); // $ method=f
function_trait_bounds::f(); function_trait_bounds::f(); // $ method=f
trait_associated_type::f(); trait_associated_type::f(); // $ method=f
generic_enum::f(); generic_enum::f(); // $ method=f
method_supertraits::f(); method_supertraits::f(); // $ method=f
function_trait_bounds_2::f(); function_trait_bounds_2::f(); // $ method=f
option_methods::f(); option_methods::f(); // $ method=f
method_call_type_conversion::f(); method_call_type_conversion::f(); // $ method=f
trait_implicit_self_borrow::f(); trait_implicit_self_borrow::f(); // $ method=f
implicit_self_borrow::f(); implicit_self_borrow::f(); // $ method=f
borrowed_typed::f(); borrowed_typed::f(); // $ method=f
try_expressions::f(); try_expressions::f(); // $ method=f
builtins::f(); builtins::f(); // $ method=f
operators::f(); operators::f(); // $ method=f
async_::f(); async_::f(); // $ method=f
impl_trait::f(); impl_trait::f(); // $ method=f
indexers::f(); indexers::f(); // $ method=f
loops::f(); loops::f(); // $ method=f
macros::f(); macros::f(); // $ method=f
method_determined_by_argument_type::f(); method_determined_by_argument_type::f(); // $ method=f
dereference::test(); dereference::test(); // $ method=test
} }

View File

@@ -28,8 +28,10 @@ module ResolveTest implements TestSig {
source.fromSource() and source.fromSource() and
not source.isFromMacroExpansion() not source.isFromMacroExpansion()
| |
target = resolveMethodCallTarget(source) and target = source.(Call).getStaticTarget() and
functionHasValue(target, value) and functionHasValue(target, value) and
// `isFromMacroExpansion` does not always work
not target.(Function).getName().getText() = ["panic_fmt", "_print", "format", "must_use"] and
tag = "method" tag = "method"
or or
target = resolveStructFieldExpr(source) and target = resolveStructFieldExpr(source) and