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 7f641a0024e..451f684ecd4 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 1710f4e3cec..ead96a89ab2 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 670a2740811..0346db8432c 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 451f684ecd4..116bc648db0 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 ead96a89ab2..ae33df976af 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 61b5c40e6e5..75a35c2a5f0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -49,7 +49,10 @@ namespace Semmle.Extraction.CSharp.Entities } } - 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 a5d208fc86f..8b099261a10 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -115,9 +115,10 @@ namespace Semmle.Extraction.CSharp.Entities 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 02018c260a6..746ea6acd2f 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 116bc648db0..565683622da 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 ae33df976af..d41369ddcd4 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 0346db8432c..d97852d7b3b 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 4fa035446ef..462fd806788 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -29,7 +29,10 @@ namespace Semmle.Extraction.CSharp.Entities 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 @@ namespace Semmle.Extraction.CSharp.Entities 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 3d07c7d42de..13e86792fc3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs @@ -15,7 +15,10 @@ namespace Semmle.Extraction.CSharp.Entities 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 e37d16567e1..40a40aab556 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -26,7 +26,10 @@ namespace Semmle.Extraction.CSharp.Entities 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 ef0d0673ce2..44e7c3cf4ca 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 6c11ac4869a..97c22cd9127 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 9d7f3330151..86bd4d542b9 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 288fe1bfe98..c8fd4ac9ab0 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 00000000000..72aa663febe --- /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.