diff --git a/csharp/ql/src/Telemetry/DatabaseQuality.qll b/csharp/ql/src/Telemetry/DatabaseQuality.qll index 1ca553ffd314..eba5ebb52114 100644 --- a/csharp/ql/src/Telemetry/DatabaseQuality.qll +++ b/csharp/ql/src/Telemetry/DatabaseQuality.qll @@ -68,15 +68,25 @@ module CallTargetStats implements StatsSig { ) } - private predicate isInitializedWithCollectionInitializer(PropertyCall c) { + private predicate isInitializedWithObjectOrCollectionInitializer(PropertyCall c) { exists(Property p, AssignExpr assign | p = c.getProperty() and assign = c.getParent() and assign.getLValue() = c and - assign.getRValue() instanceof CollectionInitializer + assign.getRValue() instanceof ObjectOrCollectionInitializer ) } + private predicate isEventFieldAccess(EventCall c) { + exists(Event e | c.getEvent() = e | + forall(Accessor a | e.getAnAccessor() = a | a.isCompilerGenerated()) + ) + } + + private predicate isTypeParameterInstantiation(ObjectCreation e) { + e.getType() instanceof TypeParameter + } + additional predicate isNotOkCall(Call c) { not exists(c.getTarget()) and not c instanceof DelegateCall and @@ -84,8 +94,10 @@ module CallTargetStats implements StatsSig { not isNoSetterPropertyCallInConstructor(c) and not isNoSetterPropertyInitialization(c) and not isAnonymousObjectMemberDeclaration(c) and - not isInitializedWithCollectionInitializer(c) and - not c.getParent+() instanceof NameOfExpr + not isInitializedWithObjectOrCollectionInitializer(c) and + not c.getParent+() instanceof NameOfExpr and + not isEventFieldAccess(c) and + not isTypeParameterInstantiation(c) } int getNumberOfNotOk() { result = count(Call c | isNotOkCall(c)) } diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected index e69de29bb2d1..205022b71802 100644 --- a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected @@ -0,0 +1,4 @@ +| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer | +| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer | +| Quality.cs:32:9:32:21 | access to indexer | Call without target $@. | Quality.cs:32:9:32:21 | access to indexer | access to indexer | +| Quality.cs:34:21:34:25 | object creation of type null | Call without target $@. | Quality.cs:34:21:34:25 | object creation of type null | object creation of type null | diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected index 28f090d3d3d9..84b6994e033a 100644 --- a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected @@ -4,4 +4,12 @@ | Quality.cs:15:24:15:34 | access to property MyProperty3 | Call without target $@. | Quality.cs:15:24:15:34 | access to property MyProperty3 | access to property MyProperty3 | | Quality.cs:15:24:15:46 | access to property MyProperty2 | Call without target $@. | Quality.cs:15:24:15:46 | access to property MyProperty2 | access to property MyProperty2 | | Quality.cs:19:13:19:23 | access to property MyProperty4 | Call without target $@. | Quality.cs:19:13:19:23 | access to property MyProperty4 | access to property MyProperty4 | -| Quality.cs:24:16:24:26 | access to property MyProperty2 | Call without target $@. | Quality.cs:24:16:24:26 | access to property MyProperty2 | access to property MyProperty2 | +| Quality.cs:20:13:20:23 | access to property MyProperty6 | Call without target $@. | Quality.cs:20:13:20:23 | access to property MyProperty6 | access to property MyProperty6 | +| Quality.cs:23:9:23:14 | access to event Event1 | Call without target $@. | Quality.cs:23:9:23:14 | access to event Event1 | access to event Event1 | +| Quality.cs:23:9:23:30 | delegate call | Call without target $@. | Quality.cs:23:9:23:30 | delegate call | delegate call | +| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer | +| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer | +| Quality.cs:32:9:32:21 | access to indexer | Call without target $@. | Quality.cs:32:9:32:21 | access to indexer | access to indexer | +| Quality.cs:34:21:34:25 | object creation of type null | Call without target $@. | Quality.cs:34:21:34:25 | object creation of type null | object creation of type null | +| Quality.cs:38:16:38:26 | access to property MyProperty2 | Call without target $@. | Quality.cs:38:16:38:26 | access to property MyProperty2 | access to property MyProperty2 | +| Quality.cs:50:20:50:26 | object creation of type T | Call without target $@. | Quality.cs:50:20:50:26 | object creation of type T | object creation of type T | diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs index 18d0ec678b62..c3ec759d6879 100644 --- a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs @@ -16,8 +16,22 @@ public Test() new Test() { - MyProperty4 = { 1, 2, 3 } + MyProperty4 = { 1, 2, 3 }, + MyProperty6 = { [1] = "" } }; + + Event1.Invoke(this, 5); + + var str = "abcd"; + var sub = str[..3]; // TODO: this is not an indexer call, but rather a `str.Substring(0, 3)` call. + + Span sp = null; + var slice = sp[..3]; // TODO: this is not an indexer call, but rather a `sp.Slice(0, 3)` call. + + Span guidBytes = stackalloc byte[16]; + guidBytes[08] = 1; // TODO: this indexer call has no target, because the target is a `ref` returning getter. + + new MyList([new(), new Test()]); // TODO: the `new()` call has no target, which is unexpected, as we know at compile time, that this is a `new Test()` call. } public int MyProperty1 { get; } @@ -25,4 +39,20 @@ public Test() public Test MyProperty3 { get; set; } public List MyProperty4 { get; } static int MyProperty5 { get; } + public Dictionary MyProperty6 { get; } + + public event EventHandler Event1; + + class Gen where T : new() + { + public static T Factory() + { + return new T(); + } + } + + class MyList + { + public MyList(IEnumerable init) { } + } }