From b9eae31172e8d01a21e0e748c9eed8305826a6b4 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 9 Oct 2025 10:44:08 +0200 Subject: [PATCH 1/7] C#: Add parameter locations test. --- csharp/ql/test/library-tests/locations/A.cs | 4 +-- .../locations/locations.expected | 34 +++++++++++++++++++ .../test/library-tests/locations/locations.ql | 4 +++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/library-tests/locations/A.cs b/csharp/ql/test/library-tests/locations/A.cs index 7f641a0024e8..451f684ecd40 100644 --- a/csharp/ql/test/library-tests/locations/A.cs +++ b/csharp/ql/test/library-tests/locations/A.cs @@ -5,8 +5,8 @@ public abstract class A public abstract T Prop { get; } public abstract T this[int index] { get; set; } public abstract event EventHandler Event; - public void Apply(T t) { } - public abstract object ToObject(T t); + public void Apply(T t1) { } + public abstract object ToObject(T t2); } public class A2 : A diff --git a/csharp/ql/test/library-tests/locations/locations.expected b/csharp/ql/test/library-tests/locations/locations.expected index 1710f4e3cec3..ead96a89ab2e 100644 --- a/csharp/ql/test/library-tests/locations/locations.expected +++ b/csharp/ql/test/library-tests/locations/locations.expected @@ -104,3 +104,37 @@ tupletype_location | Multiple1.cs:7:19:7:31 | (Int32,String) | Multiple1.cs:7:19:7:31 | Multiple1.cs:7:19:7:31 | | Multiple1.cs:7:19:7:31 | (Int32,String) | Multiple2.cs:9:9:9:21 | Multiple2.cs:9:9:9:21 | | Multiple1.cs:10:9:10:18 | (Int32,Int32) | Multiple1.cs:10:9:10:18 | Multiple1.cs:10:9:10:18 | +parameter_locations +| A.cs:6:41:6:43 | get_Item | A.cs:6:32:6:36 | index | A.cs:6:32:6:36 | A.cs:6:32:6:36 | +| A.cs:6:41:6:43 | get_Item | A.cs:6:32:6:36 | index | A.cs:6:32:6:36 | A.cs:6:32:6:36 | +| A.cs:6:41:6:43 | get_Item | A.cs:6:32:6:36 | index | A.cs:6:32:6:36 | A.cs:6:32:6:36 | +| A.cs:6:46:6:48 | set_Item | A.cs:6:32:6:36 | index | A.cs:6:32:6:36 | A.cs:6:32:6:36 | +| A.cs:6:46:6:48 | set_Item | A.cs:6:32:6:36 | index | A.cs:6:32:6:36 | A.cs:6:32:6:36 | +| A.cs:6:46:6:48 | set_Item | A.cs:6:32:6:36 | index | A.cs:6:32:6:36 | A.cs:6:32:6:36 | +| A.cs:6:46:6:48 | set_Item | A.cs:6:46:6:48 | value | A.cs:6:46:6:48 | A.cs:6:46:6:48 | +| A.cs:6:46:6:48 | set_Item | A.cs:6:46:6:48 | value | A.cs:6:46:6:48 | A.cs:6:46:6:48 | +| A.cs:6:46:6:48 | set_Item | A.cs:6:46:6:48 | value | A.cs:6:46:6:48 | A.cs:6:46:6:48 | +| A.cs:7:40:7:44 | add_Event | A.cs:7:40:7:44 | value | A.cs:7:40:7:44 | A.cs:7:40:7:44 | +| A.cs:7:40:7:44 | add_Event | A.cs:7:40:7:44 | value | A.cs:7:40:7:44 | A.cs:7:40:7:44 | +| A.cs:7:40:7:44 | add_Event | A.cs:7:40:7:44 | value | A.cs:7:40:7:44 | A.cs:7:40:7:44 | +| A.cs:7:40:7:44 | remove_Event | A.cs:7:40:7:44 | value | A.cs:7:40:7:44 | A.cs:7:40:7:44 | +| A.cs:7:40:7:44 | remove_Event | A.cs:7:40:7:44 | value | A.cs:7:40:7:44 | A.cs:7:40:7:44 | +| A.cs:7:40:7:44 | remove_Event | A.cs:7:40:7:44 | value | A.cs:7:40:7:44 | A.cs:7:40:7:44 | +| A.cs:8:17:8:21 | Apply | A.cs:8:25:8:26 | t1 | A.cs:8:25:8:26 | A.cs:8:25:8:26 | +| A.cs:8:17:8:21 | Apply | A.cs:8:25:8:26 | t1 | A.cs:8:25:8:26 | A.cs:8:25:8:26 | +| A.cs:8:17:8:21 | Apply | A.cs:8:25:8:26 | t1 | A.cs:8:25:8:26 | A.cs:8:25:8:26 | +| A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | +| A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | +| A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | +| A.cs:18:9:18:11 | get_Item | A.cs:16:37:16:37 | i | A.cs:16:37:16:37 | A.cs:16:37:16:37 | +| A.cs:19:9:19:11 | set_Item | A.cs:16:37:16:37 | i | A.cs:16:37:16:37 | A.cs:16:37:16:37 | +| A.cs:19:9:19:11 | set_Item | A.cs:19:9:19:11 | value | A.cs:19:9:19:11 | A.cs:19:9:19:11 | +| A.cs:24:9:24:11 | add_Event | A.cs:24:9:24:11 | value | A.cs:24:9:24:11 | A.cs:24:9:24:11 | +| A.cs:25:9:25:14 | remove_Event | A.cs:25:9:25:14 | value | A.cs:25:9:25:14 | A.cs:25:9:25:14 | +| A.cs:28:28:28:35 | ToObject | A.cs:28:44:28:44 | t | A.cs:28:44:28:44 | A.cs:28:44:28:44 | +| B.cs:9:9:9:11 | get_Item | B.cs:7:34:7:34 | i | B.cs:7:34:7:34 | B.cs:7:34:7:34 | +| B.cs:10:9:10:11 | set_Item | B.cs:7:34:7:34 | i | B.cs:7:34:7:34 | B.cs:7:34:7:34 | +| B.cs:10:9:10:11 | set_Item | B.cs:10:9:10:11 | value | B.cs:10:9:10:11 | B.cs:10:9:10:11 | +| B.cs:15:9:15:11 | add_Event | B.cs:15:9:15:11 | value | B.cs:15:9:15:11 | B.cs:15:9:15:11 | +| B.cs:16:9:16:14 | remove_Event | B.cs:16:9:16:14 | value | B.cs:16:9:16:14 | B.cs:16:9:16:14 | +| B.cs:19:28:19:35 | ToObject | B.cs:19:41:19:41 | t | B.cs:19:41:19:41 | B.cs:19:41:19:41 | diff --git a/csharp/ql/test/library-tests/locations/locations.ql b/csharp/ql/test/library-tests/locations/locations.ql index 670a27408115..0346db8432cd 100644 --- a/csharp/ql/test/library-tests/locations/locations.ql +++ b/csharp/ql/test/library-tests/locations/locations.ql @@ -26,3 +26,7 @@ query predicate calltype_location(Call call, Type t, SourceLocation l) { query predicate typeparameter_location(TypeParameter tp, SourceLocation l) { tp.getALocation() = l } query predicate tupletype_location(TupleType tt, SourceLocation l) { tt.getALocation() = l } + +query predicate parameter_locations(Callable c, Parameter p, SourceLocation l) { + p.getCallable() = c and p.getALocation() = l +} From f200c3ce850ca72d640762898303063135984288 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 9 Oct 2025 10:48:34 +0200 Subject: [PATCH 2/7] C#: Add field location example. --- csharp/ql/test/library-tests/locations/A.cs | 1 + .../locations/locations.expected | 43 ++++++++++--------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/csharp/ql/test/library-tests/locations/A.cs b/csharp/ql/test/library-tests/locations/A.cs index 451f684ecd40..116bc648db06 100644 --- a/csharp/ql/test/library-tests/locations/A.cs +++ b/csharp/ql/test/library-tests/locations/A.cs @@ -7,6 +7,7 @@ public abstract class A public abstract event EventHandler Event; public void Apply(T t1) { } public abstract object ToObject(T t2); + public object Field; } public class A2 : A diff --git a/csharp/ql/test/library-tests/locations/locations.expected b/csharp/ql/test/library-tests/locations/locations.expected index ead96a89ab2e..ae33df976afb 100644 --- a/csharp/ql/test/library-tests/locations/locations.expected +++ b/csharp/ql/test/library-tests/locations/locations.expected @@ -4,21 +4,24 @@ member_locations | A.cs:3:23:3:26 | A | A.cs:7:40:7:44 | Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | | A.cs:3:23:3:26 | A | A.cs:8:17:8:21 | Apply | A.cs:8:17:8:21 | A.cs:8:17:8:21 | | A.cs:3:23:3:26 | A | A.cs:9:28:9:35 | ToObject | A.cs:9:28:9:35 | A.cs:9:28:9:35 | +| A.cs:3:23:3:26 | A | A.cs:10:19:10:23 | Field | A.cs:10:19:10:23 | A.cs:10:19:10:23 | | A.cs:3:23:3:26 | A | A.cs:5:23:5:26 | Prop | A.cs:5:23:5:26 | A.cs:5:23:5:26 | | A.cs:3:23:3:26 | A | A.cs:6:23:6:26 | Item | A.cs:6:23:6:26 | A.cs:6:23:6:26 | | A.cs:3:23:3:26 | A | A.cs:7:40:7:44 | Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | | A.cs:3:23:3:26 | A | A.cs:8:17:8:21 | Apply | A.cs:8:17:8:21 | A.cs:8:17:8:21 | | A.cs:3:23:3:26 | A | A.cs:9:28:9:35 | ToObject | A.cs:9:28:9:35 | A.cs:9:28:9:35 | +| A.cs:3:23:3:26 | A | A.cs:10:19:10:23 | Field | A.cs:10:19:10:23 | A.cs:10:19:10:23 | | A.cs:3:23:3:26 | A`1 | A.cs:5:23:5:26 | Prop | A.cs:5:23:5:26 | A.cs:5:23:5:26 | | A.cs:3:23:3:26 | A`1 | A.cs:6:23:6:26 | Item | A.cs:6:23:6:26 | A.cs:6:23:6:26 | | A.cs:3:23:3:26 | A`1 | A.cs:7:40:7:44 | Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | | A.cs:3:23:3:26 | A`1 | A.cs:8:17:8:21 | Apply | A.cs:8:17:8:21 | A.cs:8:17:8:21 | | A.cs:3:23:3:26 | A`1 | A.cs:9:28:9:35 | ToObject | A.cs:9:28:9:35 | A.cs:9:28:9:35 | -| A.cs:12:14:12:15 | A2 | A.cs:14:28:14:31 | Prop | A.cs:14:28:14:31 | A.cs:14:28:14:31 | -| A.cs:12:14:12:15 | A2 | A.cs:16:28:16:31 | Item | A.cs:16:28:16:31 | A.cs:16:28:16:31 | -| A.cs:12:14:12:15 | A2 | A.cs:22:40:22:44 | Event | A.cs:22:40:22:44 | A.cs:22:40:22:44 | -| A.cs:12:14:12:15 | A2 | A.cs:28:28:28:35 | ToObject | A.cs:28:28:28:35 | A.cs:28:28:28:35 | -| A.cs:12:14:12:15 | A2 | A.cs:30:17:30:17 | M | A.cs:30:17:30:17 | A.cs:30:17:30:17 | +| A.cs:3:23:3:26 | A`1 | A.cs:10:19:10:23 | Field | A.cs:10:19:10:23 | A.cs:10:19:10:23 | +| A.cs:13:14:13:15 | A2 | A.cs:15:28:15:31 | Prop | A.cs:15:28:15:31 | A.cs:15:28:15:31 | +| A.cs:13:14:13:15 | A2 | A.cs:17:28:17:31 | Item | A.cs:17:28:17:31 | A.cs:17:28:17:31 | +| A.cs:13:14:13:15 | A2 | A.cs:23:40:23:44 | Event | A.cs:23:40:23:44 | A.cs:23:40:23:44 | +| A.cs:13:14:13:15 | A2 | A.cs:29:28:29:35 | ToObject | A.cs:29:28:29:35 | A.cs:29:28:29:35 | +| A.cs:13:14:13:15 | A2 | A.cs:31:17:31:17 | M | A.cs:31:17:31:17 | A.cs:31:17:31:17 | | B.cs:3:14:3:14 | B | B.cs:5:25:5:28 | Prop | B.cs:5:25:5:28 | B.cs:5:25:5:28 | | B.cs:3:14:3:14 | B | B.cs:7:25:7:28 | Item | B.cs:7:25:7:28 | B.cs:7:25:7:28 | | B.cs:3:14:3:14 | B | B.cs:13:40:13:44 | Event | B.cs:13:40:13:44 | B.cs:13:40:13:44 | @@ -47,11 +50,11 @@ accessor_location | A.cs:3:23:3:26 | A`1 | A.cs:6:46:6:48 | set_Item | A.cs:6:46:6:48 | A.cs:6:46:6:48 | | A.cs:3:23:3:26 | A`1 | A.cs:7:40:7:44 | add_Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | | A.cs:3:23:3:26 | A`1 | A.cs:7:40:7:44 | remove_Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | -| A.cs:12:14:12:15 | A2 | A.cs:14:36:14:37 | get_Prop | A.cs:14:36:14:37 | A.cs:14:36:14:37 | -| A.cs:12:14:12:15 | A2 | A.cs:18:9:18:11 | get_Item | A.cs:18:9:18:11 | A.cs:18:9:18:11 | -| A.cs:12:14:12:15 | A2 | A.cs:19:9:19:11 | set_Item | A.cs:19:9:19:11 | A.cs:19:9:19:11 | -| A.cs:12:14:12:15 | A2 | A.cs:24:9:24:11 | add_Event | A.cs:24:9:24:11 | A.cs:24:9:24:11 | -| A.cs:12:14:12:15 | A2 | A.cs:25:9:25:14 | remove_Event | A.cs:25:9:25:14 | A.cs:25:9:25:14 | +| A.cs:13:14:13:15 | A2 | A.cs:15:36:15:37 | get_Prop | A.cs:15:36:15:37 | A.cs:15:36:15:37 | +| A.cs:13:14:13:15 | A2 | A.cs:19:9:19:11 | get_Item | A.cs:19:9:19:11 | A.cs:19:9:19:11 | +| A.cs:13:14:13:15 | A2 | A.cs:20:9:20:11 | set_Item | A.cs:20:9:20:11 | A.cs:20:9:20:11 | +| A.cs:13:14:13:15 | A2 | A.cs:25:9:25:11 | add_Event | A.cs:25:9:25:11 | A.cs:25:9:25:11 | +| A.cs:13:14:13:15 | A2 | A.cs:26:9:26:14 | remove_Event | A.cs:26:9:26:14 | A.cs:26:9:26:14 | | B.cs:3:14:3:14 | B | B.cs:5:33:5:33 | get_Prop | B.cs:5:33:5:33 | B.cs:5:33:5:33 | | B.cs:3:14:3:14 | B | B.cs:9:9:9:11 | get_Item | B.cs:9:9:9:11 | B.cs:9:9:9:11 | | B.cs:3:14:3:14 | B | B.cs:10:9:10:11 | set_Item | B.cs:10:9:10:11 | B.cs:10:9:10:11 | @@ -62,7 +65,7 @@ type_location | A.cs:3:23:3:26 | A | A.cs:3:23:3:26 | A.cs:3:23:3:26 | | A.cs:3:23:3:26 | A`1 | A.cs:3:23:3:26 | A.cs:3:23:3:26 | | A.cs:3:25:3:25 | T | A.cs:3:25:3:25 | A.cs:3:25:3:25 | -| A.cs:12:14:12:15 | A2 | A.cs:12:14:12:15 | A.cs:12:14:12:15 | +| A.cs:13:14:13:15 | A2 | A.cs:13:14:13:15 | A.cs:13:14:13:15 | | B.cs:3:14:3:14 | B | B.cs:3:14:3:14 | B.cs:3:14:3:14 | | Base.cs:1:23:1:29 | Base | Base.cs:1:23:1:29 | Base.cs:1:23:1:29 | | Base.cs:1:23:1:29 | Base`1 | Base.cs:1:23:1:29 | Base.cs:1:23:1:29 | @@ -87,11 +90,11 @@ type_location | Multiple2.cs:5:14:5:30 | Multiple2Specific | Multiple2.cs:5:14:5:30 | Multiple2.cs:5:14:5:30 | | Sub.cs:1:14:1:16 | Sub | Sub.cs:1:14:1:16 | Sub.cs:1:14:1:16 | calltype_location -| A.cs:12:14:12:15 | call to constructor A | A.cs:3:23:3:26 | A | A.cs:3:23:3:26 | A.cs:3:23:3:26 | -| A.cs:32:20:32:24 | object creation of type A2 | A.cs:12:14:12:15 | A2 | A.cs:12:14:12:15 | A.cs:12:14:12:15 | +| A.cs:13:14:13:15 | call to constructor A | A.cs:3:23:3:26 | A | A.cs:3:23:3:26 | A.cs:3:23:3:26 | +| A.cs:33:20:33:24 | object creation of type A2 | A.cs:13:14:13:15 | A2 | A.cs:13:14:13:15 | A.cs:13:14:13:15 | | B.cs:3:14:3:14 | call to constructor A | A.cs:3:23:3:26 | A | A.cs:3:23:3:26 | A.cs:3:23:3:26 | | C.cs:7:15:7:21 | object creation of type B | B.cs:3:14:3:14 | B | B.cs:3:14:3:14 | B.cs:3:14:3:14 | -| C.cs:9:17:9:24 | object creation of type A2 | A.cs:12:14:12:15 | A2 | A.cs:12:14:12:15 | A.cs:12:14:12:15 | +| C.cs:9:17:9:24 | object creation of type A2 | A.cs:13:14:13:15 | A2 | A.cs:13:14:13:15 | A.cs:13:14:13:15 | | Sub.cs:1:14:1:16 | call to constructor Base | Base.cs:1:23:1:29 | Base | Base.cs:1:23:1:29 | Base.cs:1:23:1:29 | | Sub.cs:6:17:6:31 | object creation of type InnerBase | Base.cs:5:18:5:26 | InnerBase | Base.cs:5:18:5:26 | Base.cs:5:18:5:26 | typeparameter_location @@ -126,12 +129,12 @@ parameter_locations | A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | | A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | | A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | -| A.cs:18:9:18:11 | get_Item | A.cs:16:37:16:37 | i | A.cs:16:37:16:37 | A.cs:16:37:16:37 | -| A.cs:19:9:19:11 | set_Item | A.cs:16:37:16:37 | i | A.cs:16:37:16:37 | A.cs:16:37:16:37 | -| A.cs:19:9:19:11 | set_Item | A.cs:19:9:19:11 | value | A.cs:19:9:19:11 | A.cs:19:9:19:11 | -| A.cs:24:9:24:11 | add_Event | A.cs:24:9:24:11 | value | A.cs:24:9:24:11 | A.cs:24:9:24:11 | -| A.cs:25:9:25:14 | remove_Event | A.cs:25:9:25:14 | value | A.cs:25:9:25:14 | A.cs:25:9:25:14 | -| A.cs:28:28:28:35 | ToObject | A.cs:28:44:28:44 | t | A.cs:28:44:28:44 | A.cs:28:44:28:44 | +| A.cs:19:9:19:11 | get_Item | A.cs:17:37:17:37 | i | A.cs:17:37:17:37 | A.cs:17:37:17:37 | +| A.cs:20:9:20:11 | set_Item | A.cs:17:37:17:37 | i | A.cs:17:37:17:37 | A.cs:17:37:17:37 | +| A.cs:20:9:20:11 | set_Item | A.cs:20:9:20:11 | value | A.cs:20:9:20:11 | A.cs:20:9:20:11 | +| A.cs:25:9:25:11 | add_Event | A.cs:25:9:25:11 | value | A.cs:25:9:25:11 | A.cs:25:9:25:11 | +| A.cs:26:9:26:14 | remove_Event | A.cs:26:9:26:14 | value | A.cs:26:9:26:14 | A.cs:26:9:26:14 | +| A.cs:29:28:29:35 | ToObject | A.cs:29:44:29:44 | t | A.cs:29:44:29:44 | A.cs:29:44:29:44 | | B.cs:9:9:9:11 | get_Item | B.cs:7:34:7:34 | i | B.cs:7:34:7:34 | B.cs:7:34:7:34 | | B.cs:10:9:10:11 | set_Item | B.cs:7:34:7:34 | i | B.cs:7:34:7:34 | B.cs:7:34:7:34 | | B.cs:10:9:10:11 | set_Item | B.cs:10:9:10:11 | value | B.cs:10:9:10:11 | B.cs:10:9:10:11 | From 051b83f036edd65f84b6dc78c0b3a1a4f2858ded Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 9 Oct 2025 11:44:57 +0200 Subject: [PATCH 3/7] C#: Only extract the unbound location for fields and parameters and use this location in the QL code. --- csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs | 5 ++++- .../extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs | 5 +++-- csharp/ql/lib/semmle/code/csharp/Variable.qll | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index 61b5c40e6e50..75a35c2a5f02 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -49,7 +49,10 @@ public override void Populate(TextWriter trapFile) } } - WriteLocationsToTrap(trapFile.field_location, this, Locations); + if (Context.ExtractLocation(Symbol)) + { + WriteLocationsToTrap(trapFile.field_location, this, Locations); + } if (!IsSourceDeclaration || !Symbol.FromSource()) return; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index a5d208fc86fe..8b099261a10e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -115,9 +115,10 @@ public override void Populate(TextWriter trapFile) var type = Type.Create(Context, Symbol.Type); trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, Parent!, Original); - foreach (var l in Symbol.Locations) + if (Context.ExtractLocation(Symbol)) { - WriteLocationToTrap(trapFile.param_location, this, Context.CreateLocation(l)); + var locations = Context.GetLocations(Symbol); + WriteLocationsToTrap(trapFile.param_location, this, locations); } if (!Symbol.Locations.Any() && diff --git a/csharp/ql/lib/semmle/code/csharp/Variable.qll b/csharp/ql/lib/semmle/code/csharp/Variable.qll index 02018c260a68..746ea6acd2f6 100644 --- a/csharp/ql/lib/semmle/code/csharp/Variable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Variable.qll @@ -213,7 +213,7 @@ class Parameter extends LocalScopeVariable, Attributable, TopLevelExprParent, @p params(this, _, getTypeRef(result), _, _, _, _) } - override Location getALocation() { param_location(this, result) } + override Location getALocation() { param_location(this.getUnboundDeclaration(), result) } override string toString() { result = this.getName() } @@ -449,7 +449,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent fields(this, _, _, _, getTypeRef(result), _) } - override Location getALocation() { field_location(this, result) } + override Location getALocation() { field_location(this.getUnboundDeclaration(), result) } override string toString() { result = Variable.super.toString() } From 02428fc46708ee1d027839ebf5bb8895e9c6d491 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 9 Oct 2025 13:59:17 +0200 Subject: [PATCH 4/7] C#: Add some location examples for constructors, destructors and operators. --- csharp/ql/test/library-tests/locations/A.cs | 4 + .../locations/locations.expected | 76 ++++++++++++++----- .../test/library-tests/locations/locations.ql | 1 - 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/csharp/ql/test/library-tests/locations/A.cs b/csharp/ql/test/library-tests/locations/A.cs index 116bc648db06..565683622da9 100644 --- a/csharp/ql/test/library-tests/locations/A.cs +++ b/csharp/ql/test/library-tests/locations/A.cs @@ -8,6 +8,10 @@ public abstract class A public void Apply(T t1) { } public abstract object ToObject(T t2); public object Field; + public A() { } + public A(T t) { } + ~A() { } + public static A operator +(A a1, A a2) { return a1; } } public class A2 : A diff --git a/csharp/ql/test/library-tests/locations/locations.expected b/csharp/ql/test/library-tests/locations/locations.expected index ae33df976afb..d41369ddcd40 100644 --- a/csharp/ql/test/library-tests/locations/locations.expected +++ b/csharp/ql/test/library-tests/locations/locations.expected @@ -5,34 +5,61 @@ member_locations | A.cs:3:23:3:26 | A | A.cs:8:17:8:21 | Apply | A.cs:8:17:8:21 | A.cs:8:17:8:21 | | A.cs:3:23:3:26 | A | A.cs:9:28:9:35 | ToObject | A.cs:9:28:9:35 | A.cs:9:28:9:35 | | A.cs:3:23:3:26 | A | A.cs:10:19:10:23 | Field | A.cs:10:19:10:23 | A.cs:10:19:10:23 | +| A.cs:3:23:3:26 | A | A.cs:11:12:11:12 | A | A.cs:11:12:11:12 | A.cs:11:12:11:12 | +| A.cs:3:23:3:26 | A | A.cs:12:12:12:12 | A | A.cs:12:12:12:12 | A.cs:12:12:12:12 | +| A.cs:3:23:3:26 | A | A.cs:13:6:13:6 | ~A | A.cs:13:6:13:6 | A.cs:13:6:13:6 | +| A.cs:3:23:3:26 | A | A.cs:14:33:14:33 | + | A.cs:14:33:14:33 | A.cs:14:33:14:33 | | A.cs:3:23:3:26 | A | A.cs:5:23:5:26 | Prop | A.cs:5:23:5:26 | A.cs:5:23:5:26 | | A.cs:3:23:3:26 | A | A.cs:6:23:6:26 | Item | A.cs:6:23:6:26 | A.cs:6:23:6:26 | | A.cs:3:23:3:26 | A | A.cs:7:40:7:44 | Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | | A.cs:3:23:3:26 | A | A.cs:8:17:8:21 | Apply | A.cs:8:17:8:21 | A.cs:8:17:8:21 | | A.cs:3:23:3:26 | A | A.cs:9:28:9:35 | ToObject | A.cs:9:28:9:35 | A.cs:9:28:9:35 | | A.cs:3:23:3:26 | A | A.cs:10:19:10:23 | Field | A.cs:10:19:10:23 | A.cs:10:19:10:23 | +| A.cs:3:23:3:26 | A | A.cs:11:12:11:12 | A | A.cs:11:12:11:12 | A.cs:11:12:11:12 | +| A.cs:3:23:3:26 | A | A.cs:12:12:12:12 | A | A.cs:12:12:12:12 | A.cs:12:12:12:12 | +| A.cs:3:23:3:26 | A | A.cs:13:6:13:6 | ~A | A.cs:13:6:13:6 | A.cs:13:6:13:6 | +| A.cs:3:23:3:26 | A | A.cs:14:33:14:33 | + | A.cs:14:33:14:33 | A.cs:14:33:14:33 | | A.cs:3:23:3:26 | A`1 | A.cs:5:23:5:26 | Prop | A.cs:5:23:5:26 | A.cs:5:23:5:26 | | A.cs:3:23:3:26 | A`1 | A.cs:6:23:6:26 | Item | A.cs:6:23:6:26 | A.cs:6:23:6:26 | | A.cs:3:23:3:26 | A`1 | A.cs:7:40:7:44 | Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | | A.cs:3:23:3:26 | A`1 | A.cs:8:17:8:21 | Apply | A.cs:8:17:8:21 | A.cs:8:17:8:21 | | A.cs:3:23:3:26 | A`1 | A.cs:9:28:9:35 | ToObject | A.cs:9:28:9:35 | A.cs:9:28:9:35 | | A.cs:3:23:3:26 | A`1 | A.cs:10:19:10:23 | Field | A.cs:10:19:10:23 | A.cs:10:19:10:23 | -| A.cs:13:14:13:15 | A2 | A.cs:15:28:15:31 | Prop | A.cs:15:28:15:31 | A.cs:15:28:15:31 | -| A.cs:13:14:13:15 | A2 | A.cs:17:28:17:31 | Item | A.cs:17:28:17:31 | A.cs:17:28:17:31 | -| A.cs:13:14:13:15 | A2 | A.cs:23:40:23:44 | Event | A.cs:23:40:23:44 | A.cs:23:40:23:44 | -| A.cs:13:14:13:15 | A2 | A.cs:29:28:29:35 | ToObject | A.cs:29:28:29:35 | A.cs:29:28:29:35 | -| A.cs:13:14:13:15 | A2 | A.cs:31:17:31:17 | M | A.cs:31:17:31:17 | A.cs:31:17:31:17 | +| A.cs:3:23:3:26 | A`1 | A.cs:11:12:11:12 | A | A.cs:11:12:11:12 | A.cs:11:12:11:12 | +| A.cs:3:23:3:26 | A`1 | A.cs:12:12:12:12 | A | A.cs:12:12:12:12 | A.cs:12:12:12:12 | +| A.cs:3:23:3:26 | A`1 | A.cs:13:6:13:6 | ~A | A.cs:13:6:13:6 | A.cs:13:6:13:6 | +| A.cs:3:23:3:26 | A`1 | A.cs:14:33:14:33 | + | A.cs:14:33:14:33 | A.cs:14:33:14:33 | +| A.cs:17:14:17:15 | A2 | A.cs:17:14:17:15 | A2 | A.cs:17:14:17:15 | A.cs:17:14:17:15 | +| A.cs:17:14:17:15 | A2 | A.cs:19:28:19:31 | Prop | A.cs:19:28:19:31 | A.cs:19:28:19:31 | +| A.cs:17:14:17:15 | A2 | A.cs:21:28:21:31 | Item | A.cs:21:28:21:31 | A.cs:21:28:21:31 | +| A.cs:17:14:17:15 | A2 | A.cs:27:40:27:44 | Event | A.cs:27:40:27:44 | A.cs:27:40:27:44 | +| A.cs:17:14:17:15 | A2 | A.cs:33:28:33:35 | ToObject | A.cs:33:28:33:35 | A.cs:33:28:33:35 | +| A.cs:17:14:17:15 | A2 | A.cs:35:17:35:17 | M | A.cs:35:17:35:17 | A.cs:35:17:35:17 | +| B.cs:3:14:3:14 | B | B.cs:3:14:3:14 | B | B.cs:3:14:3:14 | B.cs:3:14:3:14 | | B.cs:3:14:3:14 | B | B.cs:5:25:5:28 | Prop | B.cs:5:25:5:28 | B.cs:5:25:5:28 | | B.cs:3:14:3:14 | B | B.cs:7:25:7:28 | Item | B.cs:7:25:7:28 | B.cs:7:25:7:28 | | B.cs:3:14:3:14 | B | B.cs:13:40:13:44 | Event | B.cs:13:40:13:44 | B.cs:13:40:13:44 | | B.cs:3:14:3:14 | B | B.cs:19:28:19:35 | ToObject | B.cs:19:28:19:35 | B.cs:19:28:19:35 | +| Base.cs:1:23:1:29 | Base | Base.cs:1:23:1:26 | Base | Base.cs:1:23:1:26 | Base.cs:1:23:1:26 | | Base.cs:1:23:1:29 | Base | Base.cs:3:17:3:17 | M | Base.cs:3:17:3:17 | Base.cs:3:17:3:17 | | Base.cs:1:23:1:29 | Base | Base.cs:5:18:5:26 | InnerBase | Base.cs:5:18:5:26 | Base.cs:5:18:5:26 | +| Base.cs:1:23:1:29 | Base`1 | Base.cs:1:23:1:26 | Base | Base.cs:1:23:1:26 | Base.cs:1:23:1:26 | | Base.cs:1:23:1:29 | Base`1 | Base.cs:3:17:3:17 | M | Base.cs:3:17:3:17 | Base.cs:3:17:3:17 | | Base.cs:1:23:1:29 | Base`1 | Base.cs:5:18:5:26 | InnerBase | Base.cs:5:18:5:26 | Base.cs:5:18:5:26 | +| Base.cs:5:18:5:26 | InnerBase | Base.cs:5:18:5:26 | InnerBase | Base.cs:5:18:5:26 | Base.cs:5:18:5:26 | +| Base.cs:5:18:5:26 | InnerBase | Base.cs:5:18:5:26 | InnerBase | Base.cs:5:18:5:26 | Base.cs:5:18:5:26 | +| Base.cs:8:23:8:30 | Base2`1 | Base.cs:8:23:8:27 | Base2 | Base.cs:8:23:8:27 | Base.cs:8:23:8:27 | +| C.cs:3:7:3:7 | C | C.cs:3:7:3:7 | C | C.cs:3:7:3:7 | C.cs:3:7:3:7 | | C.cs:3:7:3:7 | C | C.cs:5:17:5:17 | M | C.cs:5:17:5:17 | C.cs:5:17:5:17 | +| Multiple1.cs:1:22:1:29 | Multiple | Multiple1.cs:1:22:1:29 | Multiple | Multiple1.cs:1:22:1:29 | Multiple1.cs:1:22:1:29 | +| Multiple1.cs:3:22:3:39 | MultipleGeneric`1 | Multiple1.cs:3:22:3:36 | MultipleGeneric | Multiple1.cs:3:22:3:36 | Multiple1.cs:3:22:3:36 | +| Multiple1.cs:5:14:5:30 | Multiple1Specific | Multiple1.cs:5:14:5:30 | Multiple1Specific | Multiple1.cs:5:14:5:30 | Multiple1.cs:5:14:5:30 | | Multiple1.cs:5:14:5:30 | Multiple1Specific | Multiple1.cs:7:33:7:33 | M | Multiple1.cs:7:33:7:33 | Multiple1.cs:7:33:7:33 | +| Multiple2.cs:1:22:1:29 | Multiple | Multiple1.cs:1:22:1:29 | Multiple | Multiple1.cs:1:22:1:29 | Multiple1.cs:1:22:1:29 | +| Multiple2.cs:3:22:3:39 | MultipleGeneric`1 | Multiple1.cs:3:22:3:36 | MultipleGeneric | Multiple1.cs:3:22:3:36 | Multiple1.cs:3:22:3:36 | +| Multiple2.cs:5:14:5:30 | Multiple2Specific | Multiple2.cs:5:14:5:30 | Multiple2Specific | Multiple2.cs:5:14:5:30 | Multiple2.cs:5:14:5:30 | | Multiple2.cs:5:14:5:30 | Multiple2Specific | Multiple2.cs:7:17:7:17 | M | Multiple2.cs:7:17:7:17 | Multiple2.cs:7:17:7:17 | +| Sub.cs:1:14:1:16 | Sub | Sub.cs:1:14:1:16 | Sub | Sub.cs:1:14:1:16 | Sub.cs:1:14:1:16 | | Sub.cs:1:14:1:16 | Sub | Sub.cs:3:17:3:20 | SubM | Sub.cs:3:17:3:20 | Sub.cs:3:17:3:20 | accessor_location | A.cs:3:23:3:26 | A | A.cs:5:30:5:32 | get_Prop | A.cs:5:30:5:32 | A.cs:5:30:5:32 | @@ -50,11 +77,11 @@ accessor_location | A.cs:3:23:3:26 | A`1 | A.cs:6:46:6:48 | set_Item | A.cs:6:46:6:48 | A.cs:6:46:6:48 | | A.cs:3:23:3:26 | A`1 | A.cs:7:40:7:44 | add_Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | | A.cs:3:23:3:26 | A`1 | A.cs:7:40:7:44 | remove_Event | A.cs:7:40:7:44 | A.cs:7:40:7:44 | -| A.cs:13:14:13:15 | A2 | A.cs:15:36:15:37 | get_Prop | A.cs:15:36:15:37 | A.cs:15:36:15:37 | -| A.cs:13:14:13:15 | A2 | A.cs:19:9:19:11 | get_Item | A.cs:19:9:19:11 | A.cs:19:9:19:11 | -| A.cs:13:14:13:15 | A2 | A.cs:20:9:20:11 | set_Item | A.cs:20:9:20:11 | A.cs:20:9:20:11 | -| A.cs:13:14:13:15 | A2 | A.cs:25:9:25:11 | add_Event | A.cs:25:9:25:11 | A.cs:25:9:25:11 | -| A.cs:13:14:13:15 | A2 | A.cs:26:9:26:14 | remove_Event | A.cs:26:9:26:14 | A.cs:26:9:26:14 | +| A.cs:17:14:17:15 | A2 | A.cs:19:36:19:37 | get_Prop | A.cs:19:36:19:37 | A.cs:19:36:19:37 | +| A.cs:17:14:17:15 | A2 | A.cs:23:9:23:11 | get_Item | A.cs:23:9:23:11 | A.cs:23:9:23:11 | +| A.cs:17:14:17:15 | A2 | A.cs:24:9:24:11 | set_Item | A.cs:24:9:24:11 | A.cs:24:9:24:11 | +| A.cs:17:14:17:15 | A2 | A.cs:29:9:29:11 | add_Event | A.cs:29:9:29:11 | A.cs:29:9:29:11 | +| A.cs:17:14:17:15 | A2 | A.cs:30:9:30:14 | remove_Event | A.cs:30:9:30:14 | A.cs:30:9:30:14 | | B.cs:3:14:3:14 | B | B.cs:5:33:5:33 | get_Prop | B.cs:5:33:5:33 | B.cs:5:33:5:33 | | B.cs:3:14:3:14 | B | B.cs:9:9:9:11 | get_Item | B.cs:9:9:9:11 | B.cs:9:9:9:11 | | B.cs:3:14:3:14 | B | B.cs:10:9:10:11 | set_Item | B.cs:10:9:10:11 | B.cs:10:9:10:11 | @@ -65,7 +92,7 @@ type_location | A.cs:3:23:3:26 | A | A.cs:3:23:3:26 | A.cs:3:23:3:26 | | A.cs:3:23:3:26 | A`1 | A.cs:3:23:3:26 | A.cs:3:23:3:26 | | A.cs:3:25:3:25 | T | A.cs:3:25:3:25 | A.cs:3:25:3:25 | -| A.cs:13:14:13:15 | A2 | A.cs:13:14:13:15 | A.cs:13:14:13:15 | +| A.cs:17:14:17:15 | A2 | A.cs:17:14:17:15 | A.cs:17:14:17:15 | | B.cs:3:14:3:14 | B | B.cs:3:14:3:14 | B.cs:3:14:3:14 | | Base.cs:1:23:1:29 | Base | Base.cs:1:23:1:29 | Base.cs:1:23:1:29 | | Base.cs:1:23:1:29 | Base`1 | Base.cs:1:23:1:29 | Base.cs:1:23:1:29 | @@ -90,11 +117,11 @@ type_location | Multiple2.cs:5:14:5:30 | Multiple2Specific | Multiple2.cs:5:14:5:30 | Multiple2.cs:5:14:5:30 | | Sub.cs:1:14:1:16 | Sub | Sub.cs:1:14:1:16 | Sub.cs:1:14:1:16 | calltype_location -| A.cs:13:14:13:15 | call to constructor A | A.cs:3:23:3:26 | A | A.cs:3:23:3:26 | A.cs:3:23:3:26 | -| A.cs:33:20:33:24 | object creation of type A2 | A.cs:13:14:13:15 | A2 | A.cs:13:14:13:15 | A.cs:13:14:13:15 | +| A.cs:17:14:17:15 | call to constructor A | A.cs:3:23:3:26 | A | A.cs:3:23:3:26 | A.cs:3:23:3:26 | +| A.cs:37:20:37:24 | object creation of type A2 | A.cs:17:14:17:15 | A2 | A.cs:17:14:17:15 | A.cs:17:14:17:15 | | B.cs:3:14:3:14 | call to constructor A | A.cs:3:23:3:26 | A | A.cs:3:23:3:26 | A.cs:3:23:3:26 | | C.cs:7:15:7:21 | object creation of type B | B.cs:3:14:3:14 | B | B.cs:3:14:3:14 | B.cs:3:14:3:14 | -| C.cs:9:17:9:24 | object creation of type A2 | A.cs:13:14:13:15 | A2 | A.cs:13:14:13:15 | A.cs:13:14:13:15 | +| C.cs:9:17:9:24 | object creation of type A2 | A.cs:17:14:17:15 | A2 | A.cs:17:14:17:15 | A.cs:17:14:17:15 | | Sub.cs:1:14:1:16 | call to constructor Base | Base.cs:1:23:1:29 | Base | Base.cs:1:23:1:29 | Base.cs:1:23:1:29 | | Sub.cs:6:17:6:31 | object creation of type InnerBase | Base.cs:5:18:5:26 | InnerBase | Base.cs:5:18:5:26 | Base.cs:5:18:5:26 | typeparameter_location @@ -129,12 +156,21 @@ parameter_locations | A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | | A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | | A.cs:9:28:9:35 | ToObject | A.cs:9:39:9:40 | t2 | A.cs:9:39:9:40 | A.cs:9:39:9:40 | -| A.cs:19:9:19:11 | get_Item | A.cs:17:37:17:37 | i | A.cs:17:37:17:37 | A.cs:17:37:17:37 | -| A.cs:20:9:20:11 | set_Item | A.cs:17:37:17:37 | i | A.cs:17:37:17:37 | A.cs:17:37:17:37 | -| A.cs:20:9:20:11 | set_Item | A.cs:20:9:20:11 | value | A.cs:20:9:20:11 | A.cs:20:9:20:11 | -| A.cs:25:9:25:11 | add_Event | A.cs:25:9:25:11 | value | A.cs:25:9:25:11 | A.cs:25:9:25:11 | -| A.cs:26:9:26:14 | remove_Event | A.cs:26:9:26:14 | value | A.cs:26:9:26:14 | A.cs:26:9:26:14 | -| A.cs:29:28:29:35 | ToObject | A.cs:29:44:29:44 | t | A.cs:29:44:29:44 | A.cs:29:44:29:44 | +| A.cs:12:12:12:12 | A | A.cs:12:16:12:16 | t | A.cs:12:16:12:16 | A.cs:12:16:12:16 | +| A.cs:12:12:12:12 | A | A.cs:12:16:12:16 | t | A.cs:12:16:12:16 | A.cs:12:16:12:16 | +| A.cs:12:12:12:12 | A | A.cs:12:16:12:16 | t | A.cs:12:16:12:16 | A.cs:12:16:12:16 | +| A.cs:14:33:14:33 | + | A.cs:14:40:14:41 | a1 | A.cs:14:40:14:41 | A.cs:14:40:14:41 | +| A.cs:14:33:14:33 | + | A.cs:14:40:14:41 | a1 | A.cs:14:40:14:41 | A.cs:14:40:14:41 | +| A.cs:14:33:14:33 | + | A.cs:14:40:14:41 | a1 | A.cs:14:40:14:41 | A.cs:14:40:14:41 | +| A.cs:14:33:14:33 | + | A.cs:14:49:14:50 | a2 | A.cs:14:49:14:50 | A.cs:14:49:14:50 | +| A.cs:14:33:14:33 | + | A.cs:14:49:14:50 | a2 | A.cs:14:49:14:50 | A.cs:14:49:14:50 | +| A.cs:14:33:14:33 | + | A.cs:14:49:14:50 | a2 | A.cs:14:49:14:50 | A.cs:14:49:14:50 | +| A.cs:23:9:23:11 | get_Item | A.cs:21:37:21:37 | i | A.cs:21:37:21:37 | A.cs:21:37:21:37 | +| A.cs:24:9:24:11 | set_Item | A.cs:21:37:21:37 | i | A.cs:21:37:21:37 | A.cs:21:37:21:37 | +| A.cs:24:9:24:11 | set_Item | A.cs:24:9:24:11 | value | A.cs:24:9:24:11 | A.cs:24:9:24:11 | +| A.cs:29:9:29:11 | add_Event | A.cs:29:9:29:11 | value | A.cs:29:9:29:11 | A.cs:29:9:29:11 | +| A.cs:30:9:30:14 | remove_Event | A.cs:30:9:30:14 | value | A.cs:30:9:30:14 | A.cs:30:9:30:14 | +| A.cs:33:28:33:35 | ToObject | A.cs:33:44:33:44 | t | A.cs:33:44:33:44 | A.cs:33:44:33:44 | | B.cs:9:9:9:11 | get_Item | B.cs:7:34:7:34 | i | B.cs:7:34:7:34 | B.cs:7:34:7:34 | | B.cs:10:9:10:11 | set_Item | B.cs:7:34:7:34 | i | B.cs:7:34:7:34 | B.cs:7:34:7:34 | | B.cs:10:9:10:11 | set_Item | B.cs:10:9:10:11 | value | B.cs:10:9:10:11 | B.cs:10:9:10:11 | diff --git a/csharp/ql/test/library-tests/locations/locations.ql b/csharp/ql/test/library-tests/locations/locations.ql index 0346db8432cd..d97852d7b3b5 100644 --- a/csharp/ql/test/library-tests/locations/locations.ql +++ b/csharp/ql/test/library-tests/locations/locations.ql @@ -4,7 +4,6 @@ query predicate member_locations(Type t, Member m, SourceLocation l) { t = m.getDeclaringType() and l = m.getLocation() and not l instanceof EmptyLocation and - not m instanceof Constructor and t.fromSource() } From 89681a49e638476f3841872374eb33d97c6662ee Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 9 Oct 2025 14:03:14 +0200 Subject: [PATCH 5/7] C#: Only extract the unbound locations for constructors, destructors and user defined operators and use this in the QL code. --- .../Entities/Constructor.cs | 15 +++++++++++++-- .../Entities/Destructor.cs | 5 ++++- .../Entities/UserOperator.cs | 5 ++++- csharp/ql/lib/semmle/code/csharp/Callable.qll | 6 +++--- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 4fa035446ef5..462fd8067888 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -29,7 +29,10 @@ public override void Populate(TextWriter trapFile) ContainingType!.PopulateGenerics(); trapFile.constructors(this, Symbol.ContainingType.Name, ContainingType, (Constructor)OriginalDefinition); - WriteLocationToTrap(trapFile.constructor_location, this, Location); + if (Context.ExtractLocation(Symbol) && (!IsDefault || IsBestSourceLocation)) + { + WriteLocationToTrap(trapFile.constructor_location, this, Location); + } if (MakeSynthetic) { @@ -168,7 +171,15 @@ Symbol.ContainingType.TypeKind is TypeKind.Class or TypeKind.Struct && Symbol.ContainingType.IsSourceDeclaration() && !Symbol.ContainingType.IsAnonymousType; - private bool MakeSynthetic => IsPrimary || IsDefault; + /// + /// Returns true if we consider the reporting location of this constructor entity the best + /// location of the constructor. + /// For partial classes with default constructors, Roslyn consider each partial class declaration + /// as the possible location for the implicit default constructor. + /// + private bool IsBestSourceLocation => ReportingLocation is not null && Context.IsLocationInContext(ReportingLocation); + + private bool MakeSynthetic => IsPrimary || (IsDefault && IsBestSourceLocation); [return: NotNullIfNotNull(nameof(constructor))] public static new Constructor? Create(Context cx, IMethodSymbol? constructor) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs index 3d07c7d42de9..13e86792fc35 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs @@ -15,7 +15,10 @@ public override void Populate(TextWriter trapFile) ContainingType!.PopulateGenerics(); trapFile.destructors(this, $"~{Symbol.ContainingType.Name}", ContainingType, OriginalDefinition(Context, this, Symbol)); - WriteLocationToTrap(trapFile.destructor_location, this, Location); + if (Context.ExtractLocation(Symbol)) + { + WriteLocationToTrap(trapFile.destructor_location, this, Location); + } } private static new Destructor OriginalDefinition(Context cx, Destructor original, IMethodSymbol symbol) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index e37d16567e1b..40a40aab556d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -26,7 +26,10 @@ public override void Populate(TextWriter trapFile) returnType.TypeRef, (UserOperator)OriginalDefinition); - WriteLocationsToTrap(trapFile.operator_location, this, Locations); + if (Context.ExtractLocation(Symbol)) + { + WriteLocationsToTrap(trapFile.operator_location, this, Locations); + } if (IsSourceDeclaration) { diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll index ef0d0673ce2a..44e7c3cf4ca8 100644 --- a/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -357,7 +357,7 @@ class Constructor extends Callable, Member, Attributable, @constructor { override Constructor getUnboundDeclaration() { constructors(this, _, _, result) } - override Location getALocation() { constructor_location(this, result) } + override Location getALocation() { constructor_location(this.getUnboundDeclaration(), result) } override predicate fromSource() { Member.super.fromSource() and not this.isCompilerGenerated() } @@ -450,7 +450,7 @@ class Destructor extends Callable, Member, Attributable, @destructor { override Destructor getUnboundDeclaration() { destructors(this, _, _, result) } - override Location getALocation() { destructor_location(this, result) } + override Location getALocation() { destructor_location(this.getUnboundDeclaration(), result) } override string toString() { result = Callable.super.toString() } @@ -484,7 +484,7 @@ class Operator extends Callable, Member, Attributable, Overridable, @operator { override Operator getUnboundDeclaration() { operators(this, _, _, _, _, result) } - override Location getALocation() { operator_location(this, result) } + override Location getALocation() { operator_location(this.getUnboundDeclaration(), result) } override string toString() { result = Callable.super.toString() } From e8fd843e52a65c3de69a604ee2f4500c85f86fdc Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 9 Oct 2025 16:17:17 +0200 Subject: [PATCH 6/7] C#: Update some tuple related tests. --- .../assignables/Assignables.expected | 8 -------- .../library-tests/csharp7/TupleTypes.expected | 20 ++++++++----------- .../test/library-tests/csharp7/TupleTypes.ql | 4 ++-- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/csharp/ql/test/library-tests/assignables/Assignables.expected b/csharp/ql/test/library-tests/assignables/Assignables.expected index 6c11ac4869a8..97c22cd91275 100644 --- a/csharp/ql/test/library-tests/assignables/Assignables.expected +++ b/csharp/ql/test/library-tests/assignables/Assignables.expected @@ -43,12 +43,6 @@ | Assignables.cs:92:23:92:23 | b | | Assignables.cs:92:33:92:33 | s | | Assignables.cs:95:40:95:44 | tuple | -| Assignables.cs:97:24:97:24 | Item1 | -| Assignables.cs:97:27:97:36 | Item2 | -| Assignables.cs:101:6:101:8 | Item1 | -| Assignables.cs:101:11:101:24 | Item2 | -| Assignables.cs:101:12:101:15 | Item1 | -| Assignables.cs:101:18:101:23 | Item2 | | Assignables.cs:108:13:108:13 | i | | Assignables.cs:109:14:109:14 | p | | Assignables.cs:113:25:113:25 | i | @@ -69,8 +63,6 @@ | Assignables.cs:132:13:132:13 | x | | Assignables.cs:133:29:133:29 | s | | Assignables.cs:138:19:138:19 | x | -| Discards.cs:5:6:5:8 | Item1 | -| Discards.cs:5:11:5:16 | Item2 | | Discards.cs:5:30:5:30 | x | | Discards.cs:19:14:19:14 | x | | Discards.cs:20:17:20:17 | y | diff --git a/csharp/ql/test/library-tests/csharp7/TupleTypes.expected b/csharp/ql/test/library-tests/csharp7/TupleTypes.expected index 9d7f3330151b..86bd4d542b99 100644 --- a/csharp/ql/test/library-tests/csharp7/TupleTypes.expected +++ b/csharp/ql/test/library-tests/csharp7/TupleTypes.expected @@ -1,12 +1,8 @@ -| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 0 | CSharp7.cs:96:19:96:19 | Item1 | -| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 1 | CSharp7.cs:102:22:102:46 | Item2 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:213:6:213:8 | Item1 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:213:11:213:16 | Item2 | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:62:10:62:10 | Item1 | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:62:17:62:17 | Item2 | -| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:95:19:95:19 | Item1 | -| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:95:22:95:37 | Item2 | -| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:82:17:82:17 | Item1 | -| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:82:23:82:23 | Item2 | -| (String,String) | (string, string) | ValueTuple | 2 | 0 | CSharp7.cs:87:19:87:27 | Item1 | -| (String,String) | (string, string) | ValueTuple | 2 | 1 | CSharp7.cs:87:30:87:33 | Item2 | +| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 0 | Item1 | +| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 1 | Item2 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | Item1 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | Item2 | +| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | Item1 | +| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | Item2 | +| (String,String) | (string, string) | ValueTuple | 2 | 0 | Item1 | +| (String,String) | (string, string) | ValueTuple | 2 | 1 | Item2 | diff --git a/csharp/ql/test/library-tests/csharp7/TupleTypes.ql b/csharp/ql/test/library-tests/csharp7/TupleTypes.ql index 288fe1bfe982..c8fd4ac9ab03 100644 --- a/csharp/ql/test/library-tests/csharp7/TupleTypes.ql +++ b/csharp/ql/test/library-tests/csharp7/TupleTypes.ql @@ -1,6 +1,6 @@ import csharp from TupleType tt, int i -where tt.getAnElement().fromSource() +where tt.fromSource() select tt.getName(), tt.toStringWithTypes(), tt.getUnderlyingType().toStringWithTypes(), - tt.getArity(), i, tt.getElement(i) + tt.getArity(), i, tt.getElement(i).getName() From b8c3a28de3e4fc7a6a617370ab14fd46652a52c9 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 10 Oct 2025 11:47:19 +0200 Subject: [PATCH 7/7] C#: Add change note. --- csharp/ql/lib/change-notes/2025-10-10-entity-locations.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2025-10-10-entity-locations.md diff --git a/csharp/ql/lib/change-notes/2025-10-10-entity-locations.md b/csharp/ql/lib/change-notes/2025-10-10-entity-locations.md new file mode 100644 index 000000000000..72aa663febe0 --- /dev/null +++ b/csharp/ql/lib/change-notes/2025-10-10-entity-locations.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The extraction of location information for parameters, fields, constructors, destructors and user operators has been optimized. Previously, location information was extracted multiple times for each bound generic. Now, only the location of the unbound generic declaration is extracted during the extraction phase, and the QL library explicitly reuses this location for all bound instances of the same generic.