diff --git a/rust/ql/test/library-tests/type-inference/associated_types.rs b/rust/ql/test/library-tests/type-inference/associated_types.rs index a678a531f8d4..f382f68ec26f 100644 --- a/rust/ql/test/library-tests/type-inference/associated_types.rs +++ b/rust/ql/test/library-tests/type-inference/associated_types.rs @@ -131,9 +131,9 @@ mod default_method_using_associated_type { println!("{:?}", y); let x5 = S2; - println!("{:?}", x5.m1()); // $ target=m1 type=x5.m1():A.S2 + println!("{:?}", x5.m1()); // $ target=m1 type=x5.m1()@Wrapper:S2 let x6 = S2; - println!("{:?}", x6.m2()); // $ target=m2 type=x6.m2():A.S2 + println!("{:?}", x6.m2()); // $ target=m2 type=x6.m2()@Wrapper:S2 } } @@ -400,10 +400,10 @@ mod generic_associated_type { pub fn test() { let s = S; // Call to the method in `impl` block - let _g1 = s.put(1i32); // $ target=S::put type=_g1:A.i32 + let _g1 = s.put(1i32); // $ target=S::put type=_g1@Wrapper:i32 // Call to default implementation in `trait` block - let _g2 = s.put_two(true, false); // $ target=MyTraitAssoc2::put_two MISSING: type=_g2:A.bool + let _g2 = s.put_two(true, false); // $ target=MyTraitAssoc2::put_two MISSING: type=_g2@Wrapper:bool } } @@ -534,12 +534,12 @@ mod generic_associated_type_name_clash { type Output = Result; fn get(&self) -> Self::Output { - Ok(self.0) // $ fieldof=ST type=Ok(...):Result type=Ok(...):T.Output type=Ok(...):E.Output + Ok(self.0) // $ fieldof=ST type=Ok(...)@Result:Output type=Ok(...)@Result:Output } } pub fn test() { - let _y = ST(true).get(); // $ type=_y:Result type=_y:T.bool type=_y:E.bool target=get + let _y = ST(true).get(); // $ type=_y@Result:bool type=_y@Result:bool target=get } } diff --git a/rust/ql/test/library-tests/type-inference/dereference.rs b/rust/ql/test/library-tests/type-inference/dereference.rs index 4767e07576f4..99886987d995 100644 --- a/rust/ql/test/library-tests/type-inference/dereference.rs +++ b/rust/ql/test/library-tests/type-inference/dereference.rs @@ -46,7 +46,7 @@ impl S { fn explicit_monomorphic_dereference() { // Dereference with method call let a1 = MyIntPointer { value: 34i64 }; - let _b1 = a1.deref(); // $ target=MyIntPointer::deref type=_b1:TRef.i64 + let _b1 = a1.deref(); // $ target=MyIntPointer::deref type=_b1@&:i64 // Dereference with overloaded dereference operator let a2 = MyIntPointer { value: 34i64 }; @@ -60,7 +60,7 @@ fn explicit_monomorphic_dereference() { fn explicit_polymorphic_dereference() { // Explicit dereference with type parameter let c1 = MySmartPointer { value: 'a' }; - let _d1 = c1.deref(); // $ target=MySmartPointer::deref type=_d1:TRef.char + let _d1 = c1.deref(); // $ target=MySmartPointer::deref type=_d1@&:char // Explicit dereference with type parameter let c2 = MySmartPointer { value: 'a' }; @@ -74,7 +74,7 @@ fn explicit_polymorphic_dereference() { fn explicit_ref_dereference() { // Explicit dereference with type parameter let e1 = &'a'; - let _f1 = e1.deref(); // $ target=deref type=_f1:TRef.char + let _f1 = e1.deref(); // $ target=deref type=_f1@&:char // Explicit dereference with type parameter let e2 = &'a'; @@ -88,7 +88,7 @@ fn explicit_ref_dereference() { fn explicit_box_dereference() { // Explicit dereference with type parameter let g1: Box = Box::new('a'); // $ target=new - let _h1 = g1.deref(); // $ target=deref type=_h1:TRef.char + let _h1 = g1.deref(); // $ target=deref type=_h1@&:char // Explicit dereference with type parameter let g2: Box = Box::new('a'); // $ target=new @@ -109,9 +109,9 @@ fn implicit_dereference() { let _y = x.is_positive(); // $ target=is_positive type=_y:bool let z = MySmartPointer { value: S(0i64) }; - let z_ = z.foo(); // $ target=foo type=z_:TRef.i64 + let z_ = z.foo(); // $ target=foo type=z_@&:i64 - let v = Vec::new(); // $ target=new type=v:T.i32 + let v = Vec::new(); // $ target=new type=v@Vec:i32 let mut x = MySmartPointer { value: v }; x.push(0); // $ target=push } diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index ecb4816ebb01..ddba6c53da86 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -34,7 +34,7 @@ mod field_access { fn generic_field_access() { // Explicit type argument - let x = GenericThing:: { a: S }; // $ certainType=x:A.S + let x = GenericThing:: { a: S }; // $ certainType=x@GenericThing:S println!("{:?}", x.a); // $ fieldof=GenericThing // Implicit type argument @@ -427,7 +427,7 @@ mod method_non_parametric_trait_impl { let x = call_trait_m1(thing_s1); // $ type=x:S1 target=call_trait_m1 println!("{:?}", x); - let y = call_trait_m1(thing_s2); // $ type=y:MyThing type=y:A.S2 target=call_trait_m1 + let y = call_trait_m1(thing_s2); // $ type=y:MyThing type=y@MyThing:S2 target=call_trait_m1 println!("{:?}", y.a); // $ fieldof=MyThing // First implementation @@ -566,7 +566,7 @@ mod trait_default_self_type_parameter { // The trait bound on `T` uses the default for `A` which contains `Self` fn tp_uses_default(thing: S) -> i64 { - let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a type=_ms:T.S + let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a type=_ms@Option:S 0 } @@ -575,7 +575,7 @@ mod trait_default_self_type_parameter { fn get_a_through_tp(thing: &S) { // `thing` is a `TraitWithSelfTp` through the trait hierarchy - let _ms = get_a(thing); // $ target=get_a type=_ms:T.S + let _ms = get_a(thing); // $ target=get_a type=_ms@Option:S } struct MyStruct { @@ -593,7 +593,7 @@ mod trait_default_self_type_parameter { pub fn test() { let s = MyStruct { value: 0 }; - let _ms = get_a(&s); // $ target=get_a type=_ms:T.MyStruct + let _ms = get_a(&s); // $ target=get_a type=_ms@Option:MyStruct } } @@ -871,7 +871,7 @@ mod method_supertraits { fn type_param_trait_to_supertrait>(x: T) { // Test that `MyTrait3` is a subtrait of `MyTrait1>` - let a = x.m1(); // $ target=MyTrait1::m1 type=a:MyThing type=a:A.S1 + let a = x.m1(); // $ target=MyTrait1::m1 type=a@MyThing:S1 println!("{:?}", a); } @@ -898,7 +898,7 @@ mod method_supertraits { let s = call_trait_m1(x); // $ type=s:S1 target=call_trait_m1 let x = MyThing2 { a: S2 }; - let s = call_trait_m1(x); // $ type=s:MyThing type=s:A.S2 target=call_trait_m1 + let s = call_trait_m1(x); // $ type=s@MyThing:S2 target=call_trait_m1 } } @@ -1011,20 +1011,20 @@ mod type_aliases { println!("{:?}", p1); // Type can be only inferred from the type alias - let p2: MyPair = PairOption::PairNone(); // $ certainType=p2:Fst.S1 certainType=p2:Snd.S2 + let p2: MyPair = PairOption::PairNone(); // $ certainType=p2@PairOption:S1 certainType=p2@PairOption:S2 println!("{:?}", p2); // First type from alias, second from constructor - let p3: AnotherPair<_> = PairOption::PairSnd(S3); // $ certainType=p3:Fst.S2 + let p3: AnotherPair<_> = PairOption::PairSnd(S3); // $ certainType=p3@PairOption:S2 println!("{:?}", p3); // First type from alias definition, second from argument to alias - let p3: AnotherPair = PairOption::PairNone(); // $ certainType=p3:Fst.S2 certainType=p3:Snd.S3 + let p3: AnotherPair = PairOption::PairNone(); // $ certainType=p3@PairOption:S2 certainType=p3@PairOption:S3 println!("{:?}", p3); g(PairOption::PairSnd(PairOption::PairSnd(S3))); // $ target=g - let x: S7; // $ certainType=x:Result $ certainType=x:E.S1 $ certainType=x:T.S4 $ certainType=x:T.T41.S2 $ certainType=x:T.T42.S5 $ certainType=x:T.T42.T5.S2 + let x: S7; // $ certainType=x@Result:S1 $ certainType=x@Result:S4 $ certainType=x@Result.S4:S2 $ certainType=x@Result.S4:S5 $ certainType=x@Result.S4.S5:S2 } } @@ -1068,7 +1068,7 @@ mod option_methods { struct S; pub fn f() { - let x1 = MyOption::::new(); // $ certainType=x1:T.S target=new + let x1 = MyOption::::new(); // $ certainType=x1@MyOption:S target=new println!("{:?}", x1); let mut x2 = MyOption::new(); // $ target=new @@ -1192,14 +1192,14 @@ mod method_call_type_conversion { let x7 = S(&S2); // Non-implicit dereference with nested borrow in order to test that the // implicit dereference handling doesn't affect nested borrows. - let t = x7.m1(); // $ target=m1 type=t:& type=t:TRef.S2 + let t = x7.m1(); // $ target=m1 type=t:& type=t@&:S2 println!("{:?}", x7); let x9: String = "Hello".to_string(); // $ certainType=x9:String target=to_string // Implicit `String` -> `str` conversion happens via the `Deref` trait: // https://doc.rust-lang.org/std/string/struct.String.html#deref. - let u = x9.parse::(); // $ target=parse type=u:T.u32 + let u = x9.parse::(); // $ target=parse type=u@Result:u32 let my_thing = &MyInt { a: 37 }; // implicit borrow of a `&` @@ -1382,7 +1382,7 @@ mod builtins { let z = x + y; // $ type=z:i32 target=add let z = x.abs(); // $ target=abs $ type=z:i32 let c = 'c'; // $ certainType=c:char - let hello = "Hello"; // $ certainType=hello:TRef.str + let hello = "Hello"; // $ certainType=hello@&:str let f = 123.0f64; // $ certainType=f:f64 let t = true; // $ certainType=t:bool let f = false; // $ certainType=f:bool @@ -1403,8 +1403,8 @@ mod builtins { } } - let x = [1, 2, 3].my_method(); // $ target=my_method type=x:TRef.i32 - let x = <[_; 3]>::my_method(&[1, 2, 3]); // $ target=my_method type=x:TRef.i32 + let x = [1, 2, 3].my_method(); // $ target=my_method type=x@&:i32 + let x = <[_; 3]>::my_method(&[1, 2, 3]); // $ target=my_method type=x@&:i32 let x = <[i32; 3]>::my_func(); // $ target=my_func type=x:i32 impl MyTrait for [T] { @@ -1418,8 +1418,8 @@ mod builtins { } let s: &[i32] = &[1, 2, 3]; - let x = s.my_method(); // $ target=my_method type=x:TRef.i32 - let x = <[_]>::my_method(s); // $ target=my_method type=x:TRef.i32 + let x = s.my_method(); // $ target=my_method type=x@&:i32 + let x = <[_]>::my_method(s); // $ target=my_method type=x@&:i32 let x = <[i32]>::my_func(); // $ target=my_func type=x:i32 impl MyTrait for (T, i32) { @@ -1433,8 +1433,8 @@ mod builtins { } let p = (42, 7); - let x = p.my_method(); // $ target=my_method type=x:TRef.i32 - let x = <(_, _)>::my_method(&p); // $ target=my_method type=x:TRef.i32 + let x = p.my_method(); // $ target=my_method type=x@&:i32 + let x = <(_, _)>::my_method(&p); // $ target=my_method type=x@&:i32 let x = <(i32, i32)>::my_func(); // $ target=my_func type=x:i32 impl MyTrait for &T { @@ -1448,8 +1448,8 @@ mod builtins { } let r = &42; - let x = r.my_method(); // $ target=my_method type=x:TRef.i32 - let x = <&_>::my_method(&r); // $ target=my_method type=x:TRef.i32 + let x = r.my_method(); // $ target=my_method type=x@&:i32 + let x = <&_>::my_method(&r); // $ target=my_method type=x@&:i32 let x = <&i32>::my_func(); // $ target=my_func type=x:i32 impl MyTrait for *mut T { @@ -1464,8 +1464,8 @@ mod builtins { let mut v = 42; let p: *mut i32 = &mut v; - let x = unsafe { p.my_method() }; // $ target=my_method type=x:TRef.i32 - let x = unsafe { <*mut _>::my_method(&p) }; // $ target=my_method type=x:TRef.i32 + let x = unsafe { p.my_method() }; // $ target=my_method type=x@&:i32 + let x = unsafe { <*mut _>::my_method(&p) }; // $ target=my_method type=x@&:i32 let x = <*mut i32>::my_func(); // $ target=my_func type=x:i32 } } @@ -2046,7 +2046,7 @@ mod indexers { } pub fn f() { - let mut vec = MyVec::new(); // $ type=vec:T.S target=new + let mut vec = MyVec::new(); // $ type=vec@MyVec:S target=new vec.push(S); // $ target=push vec[0].foo(); // $ target=MyVec::index target=foo @@ -2262,24 +2262,24 @@ mod loops { for i in [1, 2, 3].map(|x| x + 1) {} // $ target=map target=add type=i:i32 for i in [1, 2, 3].into_iter() {} // $ target=into_iter type=i:i32 - let vals1 = [1u8, 2, 3]; // $ type=vals1:TArray.u8 + let vals1 = [1u8, 2, 3]; // $ type=vals1@[;]:u8 for u in vals1 {} // $ type=u:u8 - let vals2 = [1u16; 3]; // $ type=vals2:TArray.u16 + let vals2 = [1u16; 3]; // $ type=vals2@[;]:u16 for u in vals2 {} // $ type=u:u16 - let vals3: [u32; 3] = [1, 2, 3]; // $ certainType=vals3:TArray.u32 + let vals3: [u32; 3] = [1, 2, 3]; // $ certainType=vals3@[;]:u32 for u in vals3 {} // $ type=u:u32 - let vals4: [u64; 3] = [1; 3]; // $ certainType=vals4:TArray.u64 + let vals4: [u64; 3] = [1; 3]; // $ certainType=vals4@[;]:u64 for u in vals4 {} // $ type=u:u64 - let mut strings1 = ["foo", "bar", "baz"]; // $ type=strings1:TArray.TRef.str - for s in &strings1 {} // $ type=s:TRef.TRef.str - for s in &mut strings1 {} // $ type=s:TRefMut.TRef.str - for s in strings1 {} // $ type=s:TRef.str + let mut strings1 = ["foo", "bar", "baz"]; // $ type=strings1@[;].&:str + for s in &strings1 {} // $ type=s@&.&:str + for s in &mut strings1 {} // $ type=s@&mut.&:str + for s in strings1 {} // $ type=s@&:str - let strings2 = // $ type=strings2:TArray.String + let strings2 = // $ type=strings2@[;]:String [ String::from("foo"), // $ target=from String::from("bar"), // $ target=from @@ -2287,15 +2287,15 @@ mod loops { ]; for s in strings2 {} // $ type=s:String - let strings3 = // $ type=strings3:TRef.TArray.String + let strings3 = // $ type=strings3@&.[;]:String &[ String::from("foo"), // $ target=from String::from("bar"), // $ target=from String::from("baz"), // $ target=from ]; - for s in strings3 {} // $ type=s:TRef.String + for s in strings3 {} // $ type=s@&:String - let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ target=new $ type=callables:TArray.MyCallable + let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ target=new $ type=callables@[;]:MyCallable for c // $ type=c:MyCallable in callables { @@ -2305,13 +2305,13 @@ mod loops { // for loops with ranges for i in 0..10 {} // $ type=i:i32 - for u in [0u8..10] {} // $ type=u:Range type=u:Idx.u8 - let range = 0..10; // $ certainType=range:Range type=range:Idx.i32 + for u in [0u8..10] {} // $ type=u:Range type=u@Range:u8 + let range = 0..10; // $ certainType=range:Range type=range@Range:i32 for i in range {} // $ type=i:i32 let range_full = ..; // $ certainType=range_full:RangeFull - for i in &[1i64, 2i64, 3i64][range_full] {} // $ target=index MISSING: type=i:TRef.i64 + for i in &[1i64, 2i64, 3i64][range_full] {} // $ target=index MISSING: type=i@&:i64 - let range1 = // $ certainType=range1:Range type=range1:Idx.u16 + let range1 = // $ certainType=range1:Range type=range1@Range:u16 std::ops::Range { start: 0u16, end: 10u16, @@ -2320,39 +2320,39 @@ mod loops { // for loops with containers - let vals3 = vec![1, 2, 3]; // $ type=vals3:Vec $ MISSING: type=vals3:T.i32 + let vals3 = vec![1, 2, 3]; // $ type=vals3:Vec $ MISSING: type=vals3@Vec:i32 for i in vals3 {} // $ MISSING: type=i:i32 - let vals4a: Vec = [1u16, 2, 3].to_vec(); // $ certainType=vals4a:Vec certainType=vals4a:T.u16 + let vals4a: Vec = [1u16, 2, 3].to_vec(); // $ certainType=vals4a@Vec:u16 for u in vals4a {} // $ type=u:u16 - 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@Vec:u16 for u in vals4b {} // $ MISSING: type=u:u16 - let vals5 = Vec::from([1u32, 2, 3]); // $ certainType=vals5:Vec target=from type=vals5:T.u32 + let vals5 = Vec::from([1u32, 2, 3]); // $ target=from type=vals5@Vec:u32 for u in vals5 {} // $ type=u:u32 - let vals6: Vec<&u64> = [1u64, 2, 3].iter().collect(); // $ certainType=vals6:Vec certainType=vals6:T.TRef.u64 - for u in vals6 {} // $ type=u:TRef.u64 + let vals6: Vec<&u64> = [1u64, 2, 3].iter().collect(); // $ certainType=vals6@Vec.&:u64 + for u in vals6 {} // $ type=u@&:u64 - let mut vals7 = Vec::new(); // $ target=new certainType=vals7:Vec type=vals7:T.u8 + let mut vals7 = Vec::new(); // $ target=new type=vals7@Vec:u8 vals7.push(1u8); // $ target=push for u in vals7 {} // $ type=u:u8 - let matrix1 = vec![vec![1, 2], vec![3, 4]]; // $ type=matrix1:Vec $ MISSING: type=matrix1:T.Vec type=matrix1:T.T.i32 + let matrix1 = vec![vec![1, 2], vec![3, 4]]; // $ type=matrix1:Vec $ MISSING: type=matrix1@Vec:Vec type=matrix1@Vec.Vec:i32 #[rustfmt::skip] - let _ = for row in matrix1 { // $ MISSING: type=row:Vec type=row:T.i32 + let _ = for row in matrix1 { // $ MISSING: type=row:Vec type=row@Vec:i32 for cell in row { // $ MISSING: type=cell:i32 } }; - let mut map1 = std::collections::HashMap::new(); // $ target=new type=map1:K.i32 type=map1:V.Box $ MISSING: type=map1:Hashmap type1=map1:V.T.TRef.str + let mut map1 = std::collections::HashMap::new(); // $ target=new type=map1@HashMap:i32 type=map1@HashMap.Box.&:str map1.insert(1, Box::new("one")); // $ target=insert target=new map1.insert(2, Box::new("two")); // $ target=insert target=new - for key in map1.keys() {} // $ target=keys type=key:TRef.i32 - for value in map1.values() {} // $ target=values type=value:TRef.Box type=value:TRef.T.TRef.str - for (key, value) in map1.iter() {} // $ target=iter type=key:TRef.i32 type=value:TRef.Box type=value:TRef.T.TRef.str - for (key, value) in &map1 {} // $ type=key:TRef.i32 type=value:TRef.Box type=value:TRef.T.TRef.str + for key in map1.keys() {} // $ target=keys type=key@&:i32 + for value in map1.values() {} // $ target=values type=value@&.Box.&:str + for (key, value) in map1.iter() {} // $ target=iter type=key@&:i32 type=value@&.Box.&:str + for (key, value) in &map1 {} // $ type=key@&:i32 type=value@&.Box.&:str // while loops @@ -2398,27 +2398,27 @@ mod explicit_type_args { } pub fn f() { - let x1: Option> = S1::assoc_fun(); // $ certainType=x1:T.T.S2 target=assoc_fun - let x2 = S1::::assoc_fun(); // $ certainType=x2:T.T.S2 target=assoc_fun - let x3 = S3::assoc_fun(); // $ certainType=x3:T.T.S2 target=assoc_fun - let x4 = S1::::method(S1::default()); // $ target=method target=default certainType=x4:T.S2 - let x5 = S3::method(S1::default()); // $ target=method target=default certainType=x5:T.S2 - let x6 = S4::(Default::default()); // $ type=x6:T4.S2 target=default - let x7 = S4(S2); // $ type=x7:T4.S2 - let x8 = S4(0); // $ type=x8:T4.i32 - let x9 = S4(S2::default()); // $ type=x9:T4.S2 target=default - let x10 = S5:: // $ certainType=x10:T5.S2 + let x1: Option> = S1::assoc_fun(); // $ certainType=x1@Option.S1:S2 target=assoc_fun + let x2 = S1::::assoc_fun(); // $ certainType=x2@Option.S1:S2 target=assoc_fun + let x3 = S3::assoc_fun(); // $ certainType=x3@Option.S1:S2 target=assoc_fun + let x4 = S1::::method(S1::default()); // $ target=method target=default certainType=x4@S1:S2 + let x5 = S3::method(S1::default()); // $ target=method target=default certainType=x5@S1:S2 + let x6 = S4::(Default::default()); // $ type=x6@S4:S2 target=default + let x7 = S4(S2); // $ type=x7@S4:S2 + let x8 = S4(0); // $ type=x8@S4:i32 + let x9 = S4(S2::default()); // $ type=x9@S4:S2 target=default + let x10 = S5:: // $ certainType=x10@S5:S2 { field: Default::default(), // $ target=default }; - let x11 = S5 { field: S2 }; // $ type=x11:T5.S2 - let x12 = S5 { field: 0 }; // $ type=x12:T5.i32 - let x13 = S5 // $ type=x13:T5.S2 + let x11 = S5 { field: S2 }; // $ type=x11@S5:S2 + let x12 = S5 { field: 0 }; // $ type=x12@S5:i32 + let x13 = S5 // $ type=x13@S5:S2 { field: S2::default(), // $ target=default }; let x14 = foo::(Default::default()); // $ certainType=x14:i32 target=default target=foo - let x15 = S1::::default(); // $ certainType=x15:T.S2 target=default + let x15 = S1::::default(); // $ certainType=x15@S1:S2 target=default } } @@ -2454,11 +2454,11 @@ mod tuples { // `a` and `b` to be inferred. let a = Default::default(); // $ target=default type=a:i64 let b = Default::default(); // $ target=default type=b:bool - let pair = (a, b); // $ type=pair:T0.i64 type=pair:T1.bool + let pair = (a, b); // $ type=pair@(T_2):i64 type=pair@(T_2):bool let i: i64 = pair.0; // $ fieldof=Tuple2 let j: bool = pair.1; // $ fieldof=Tuple2 - let pair = [1, 1].into(); // $ type=pair:(T_2) type=pair:T0.i32 type=pair:T1.i32 target=into + let pair = [1, 1].into(); // $ type=pair@(T_2):i32 type=pair@(T_2):i32 target=into match pair { (0, 0) => print!("unexpected"), _ => print!("expected"), @@ -2572,7 +2572,7 @@ mod if_expr { pub fn f(b: bool) -> Box> { let x = if b { let y = Default::default(); // $ target=default - y // $ type=y:T.i32 + y // $ type=y@S:i32 } else { S(2) }; @@ -2648,14 +2648,14 @@ mod context_typed { } pub fn f() { - let x = None; // $ type=x:T.i32 + let x = None; // $ type=x@Option:i32 let x: Option = x; - let x = Option::::None; // $ type=x:T.i32 - let x = Option::None::; // $ type=x:T.i32 + let x = Option::::None; // $ type=x@Option:i32 + let x = Option::None::; // $ type=x@Option:i32 fn pin_option(opt: Option, x: T) {} - let x = None; // $ type=x:T.i32 + let x = None; // $ type=x@Option:i32 pin_option(x, 0); // $ target=pin_option enum MyEither { @@ -2663,33 +2663,33 @@ mod context_typed { B { right: T2 }, } - let x = MyEither::A { left: 0 }; // $ type=x:T1.i32 type=x:T2.String + let x = MyEither::A { left: 0 }; // $ type=x@MyEither:i32 type=x@MyEither:String let x: MyEither = x; - let x = MyEither::<_, String>::A { left: 0 }; // $ type=x:T1.i32 certainType=x:T2.String + let x = MyEither::<_, String>::A { left: 0 }; // $ type=x@MyEither:i32 certainType=x@MyEither:String #[rustfmt::skip] - let x = MyEither::B:: { // $ certainType=x:T1.i32 type=x:T2.String + let x = MyEither::B:: { // $ certainType=x@MyEither:i32 type=x@MyEither:String right: String::new(), // $ target=new }; fn pin_my_either(e: MyEither, x: T) {} #[rustfmt::skip] - let x = MyEither::B { // $ type=x:T1.i32 type=x:T2.String + let x = MyEither::B { // $ type=x@MyEither:i32 type=x@MyEither:String right: String::new(), // $ target=new }; pin_my_either(x, 0); // $ target=pin_my_either - let x = Result::Ok(0); // $ type=x:E.String + let x = Result::Ok(0); // $ type=x@Result:String let x: Result = x; - let x = Result::::Ok(0); // $ type=x:E.String - let x = Result::Ok::(0); // $ type=x:E.String + let x = Result::::Ok(0); // $ type=x@Result:String + let x = Result::Ok::(0); // $ type=x@Result:String fn pin_result(res: Result, x: E) {} - let x = Result::Ok(0); // $ type=x:T.i32 type=x:E.bool + let x = Result::Ok(0); // $ type=x@Result:i32 type=x@Result:bool pin_result(x, false); // $ target=pin_result - let mut x = Vec::new(); // $ type=x:T.i32 target=new + let mut x = Vec::new(); // $ type=x@Vec:i32 target=new x.push(0); // $ target=push let y = Default::default(); // $ type=y:i32 target=default diff --git a/rust/ql/test/library-tests/type-inference/pattern_matching.rs b/rust/ql/test/library-tests/type-inference/pattern_matching.rs index 33e6b9f09f30..bc85b0ee96ff 100755 --- a/rust/ql/test/library-tests/type-inference/pattern_matching.rs +++ b/rust/ql/test/library-tests/type-inference/pattern_matching.rs @@ -37,18 +37,18 @@ pub fn f() -> Option<()> { let value3 = 42; if let ref mesg = value3 { - let mesg = mesg; // $ type=mesg:TRef.i32 + let mesg = mesg; // $ type=mesg@&:i32 println!("{mesg}"); } let value4 = Some(42); if let Some(ref mesg) = value4 { - let mesg = mesg; // $ type=mesg:TRef.i32 + let mesg = mesg; // $ type=mesg@&:i32 println!("{mesg}"); } let ref value5 = 42; - let x = value5; // $ type=x:TRef.i32 + let x = value5; // $ type=x@&:i32 let my_record_struct = MyRecordStruct { value1: 42, @@ -102,27 +102,27 @@ pub fn f() -> Option<()> { ) => { let a = value1; // $ type=a:bool let b = x; // $ type=b:i32 - let c = y; // $ type=c:TRef.str + let c = y; // $ type=c@&:str (); } _ => (), } - let opt1 = Some(Default::default()); // $ type=opt1:T.i32 target=default + let opt1 = Some(Default::default()); // $ type=opt1@Option:i32 target=default #[rustfmt::skip] let _ = if let Some::(x) = opt1 { x; // $ type=x:i32 }; - let opt2 = Some(Default::default()); // $ type=opt2:T.i32 target=default + let opt2 = Some(Default::default()); // $ type=opt2@Option:i32 target=default #[rustfmt::skip] let _ = if let Option::Some::(x) = opt2 { x; // $ type=x:i32 }; - let opt3 = Some(Default::default()); // $ type=opt3:T.i32 target=default + let opt3 = Some(Default::default()); // $ type=opt3@Option:i32 target=default #[rustfmt::skip] let _ = if let Option::::Some(x) = opt3 { @@ -197,7 +197,7 @@ pub fn literal_patterns() { let string_val = "hello"; match string_val { "hello" => { - let hello_match = string_val; // $ certainType=hello_match:TRef.str + let hello_match = string_val; // $ certainType=hello_match@&:str println!("String literal: {}", hello_match); } _ => {} @@ -230,7 +230,7 @@ pub fn identifier_patterns() { // IdentPat with ref match &value { ref x => { - let ref_bound = x; // $ type=ref_bound:TRef.TRef.i32 + let ref_bound = x; // $ type=ref_bound@&.&:i32 println!("Reference identifier: {:?}", ref_bound); } } @@ -269,7 +269,7 @@ pub fn identifier_patterns() { let mut ref_mut_val = 5i32; match &mut ref_mut_val { ref mut x => { - let ref_mut_bound = x; // $ type=ref_mut_bound:TRefMut.TRefMut.i32 + let ref_mut_bound = x; // $ type=ref_mut_bound@&mut.&mut:i32 **ref_mut_bound += 1; // $ target=deref target=add_assign println!("Ref mut pattern"); } @@ -341,14 +341,14 @@ pub fn reference_patterns() { match &mut mutable_value { &mut ref x => { - let mut_ref_bound = x; // $ type=mut_ref_bound:TRef.i32 + let mut_ref_bound = x; // $ type=mut_ref_bound@&:i32 println!("Mutable ref pattern: {}", mut_ref_bound); } } match &value { ref x => { - let ref_pattern = x; // $ type=ref_pattern:TRef.TRef.i32 + let ref_pattern = x; // $ type=ref_pattern@&.&:i32 println!("Reference pattern: {}", ref_pattern); } } @@ -525,7 +525,7 @@ pub fn slice_patterns() { // SlicePat - Slice patterns match slice { [] => { - let empty_slice = slice; // $ certainType=empty_slice:TRef.TSlice.i32 + let empty_slice = slice; // $ certainType=empty_slice@&.[]:i32 println!("Empty slice: {:?}", empty_slice); } [x] => { @@ -540,7 +540,7 @@ pub fn slice_patterns() { [first, middle @ .., last] => { let slice_start = *first; // $ MISSING: type=slice_start:i32 let slice_end = *last; // $ MISSING: type=slice_end:i32 - let slice_middle = middle; // $ MISSING: type=slice_middle:TRef.TSlice.i32 + let slice_middle = middle; // $ MISSING: type=slice_middle@&.[]:i32 println!( "First: {}, last: {}, middle len: {}", slice_start, @@ -717,7 +717,7 @@ pub fn complex_nested_patterns() { } // Catch-all with identifier pattern other => { - let other_complex = other; // $ type=other_complex:T0.Point type=other_complex:T1.MyOption + let other_complex = other; // $ type=other_complex@(T_2):Point type=other_complex@(T_2):MyOption println!("Other complex data: {:?}", other_complex); } } @@ -750,7 +750,7 @@ pub fn patterns_in_let_statements() { // Let with reference pattern let value = 42i32; let ref ref_val = value; - let let_ref = ref_val; // $ certainType=let_ref:TRef.i32 + let let_ref = ref_val; // $ certainType=let_ref@&:i32 // Let with mutable pattern let mut mut_val = 10i32; @@ -779,13 +779,13 @@ pub fn patterns_in_function_parameters() { // Call the functions to use them let point = Point { x: 5, y: 10 }; - let extracted = extract_point(point); // $ target=extract_point certainType=extracted:T0.i32 certainType=extracted:T1.i32 + let extracted = extract_point(point); // $ target=extract_point certainType=extracted@(T_2):i32 certainType=extracted@(T_2):i32 let color = Color(200, 100, 50); let red = extract_color(color); // $ target=extract_color certainType=red:u8 let tuple = (42i32, 3.14f64, true); - let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple certainType=tuple_extracted:T0.i32 certainType=tuple_extracted:T1.bool + let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple certainType=tuple_extracted@(T_2):i32 certainType=tuple_extracted@(T_2):bool } #[rustfmt::skip] diff --git a/rust/ql/test/library-tests/type-inference/raw_pointer.rs b/rust/ql/test/library-tests/type-inference/raw_pointer.rs index bf4537f30ce6..065396b35f57 100644 --- a/rust/ql/test/library-tests/type-inference/raw_pointer.rs +++ b/rust/ql/test/library-tests/type-inference/raw_pointer.rs @@ -12,7 +12,7 @@ fn raw_pointer_mut_deref(x: *mut bool) -> i32 { fn raw_const_borrow() { let a: i64 = 10; - let x = &raw const a; // $ type=x:TPtrConst.i64 + let x = &raw const a; // $ type=x@*const:i64 unsafe { let _y = *x; // $ type=_y:i64 } @@ -20,7 +20,7 @@ fn raw_const_borrow() { fn raw_mut_borrow() { let mut a = 10i32; - let x = &raw mut a; // $ type=x:TPtrMut.i32 + let x = &raw mut a; // $ type=x@*mut:i32 unsafe { let _y = *x; // $ type=_y:i32 } @@ -29,7 +29,7 @@ fn raw_mut_borrow() { fn raw_mut_write(cond: bool) { let a = 10i32; // The type of `ptr_written` must be inferred from the write below. - let ptr_written = null_mut(); // $ target=null_mut type=ptr_written:TPtrMut.i32 + let ptr_written = null_mut(); // $ target=null_mut type=ptr_written@*mut:i32 if cond { unsafe { // NOTE: This write is undefined behavior because `ptr_written` is a null pointer. @@ -41,7 +41,7 @@ fn raw_mut_write(cond: bool) { fn raw_type_from_deref(cond: bool) { // The type of `ptr_read` must be inferred from the read below. - let ptr_read = null_mut(); // $ target=null_mut type=ptr_read:TPtrMut.i64 + let ptr_read = null_mut(); // $ target=null_mut type=ptr_read@*mut:i64 if cond { unsafe { // NOTE: This read is undefined behavior because `ptr_read` is a null pointer. diff --git a/rust/ql/test/library-tests/type-inference/regressions.rs b/rust/ql/test/library-tests/type-inference/regressions.rs index 465475475bfb..d854f55a1adc 100644 --- a/rust/ql/test/library-tests/type-inference/regressions.rs +++ b/rust/ql/test/library-tests/type-inference/regressions.rs @@ -149,7 +149,7 @@ mod regression5 { fn foo() -> S2 { let x = S1.into(); // $ target=into - x // $ type=x:T2.S1 + x // $ type=x@S2:S1 } } @@ -176,6 +176,6 @@ mod regression6 { } fn foo() { - let x = S(0) + S(1); // $ target=add1 $ SPURIOUS: target=add2 type=x:T.T.i32 + let x = S(0) + S(1); // $ target=add1 $ SPURIOUS: target=add2 type=x@S.S:i32 } } diff --git a/rust/ql/test/library-tests/type-inference/type-inference.ql b/rust/ql/test/library-tests/type-inference/type-inference.ql index c4653f557ac7..fa07dd4471e7 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.ql +++ b/rust/ql/test/library-tests/type-inference/type-inference.ql @@ -67,7 +67,7 @@ module TypeTest implements TestSig { predicate hasActualResult(Location location, string element, string tag, string value) { none() } predicate hasOptionalResult(Location location, string element, string tag, string value) { - exists(AstNode n, TypePath path, Type t | + exists(AstNode n, TypePath path, Type t, string at | t = TypeInference::inferType(n, path) and ( tag = "type" @@ -76,11 +76,8 @@ module TypeTest implements TestSig { tag = "certainType" ) and location = n.getLocation() and - ( - if path.isEmpty() - then value = element + ":" + t - else value = element + ":" + path.toString() + "." + t.toString() - ) and + (if path.isEmpty() then at = "" else at = "@" + TypePath::printTypePathVerbose(path)) and + value = element + at + ":" + t.toString() and element = [n.toString(), n.(IdentPat).getName().getText()] ) } diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index 1f4400d8f2d7..cf82d77b5e1d 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -275,7 +275,34 @@ module Make1 Input1> { class TypePath = UnboundList; /** Provides predicates for constructing `TypePath`s. */ - module TypePath = UnboundList; + module TypePath { + import UnboundList + + private string printTypeParameterVerbose(TypeParameter tp) { + exists(Type t | + t.getATypeParameter() = tp and + result = t.toString() + "<" + tp.toString() + ">" + ) + } + + /** + * Gets a verbose textual representation of `path`, which includes the names + * of the types that the type parameters belong to. + * + * For example, the verbose textual representation of the path `"T1.T2"` is + * `"S1.S2"`, provided that `T1` is a type parameter of `S1` and `T2` + * is a type parameter of `S2`. + */ + bindingset[path] + string printTypePathVerbose(TypePath path) { + result = + concat(int i, TypeParameter e | + e = path.getElement(i) + | + printTypeParameterVerbose(e), "." order by i + ) + } + } /** * A class that has a type tree associated with it.