Skip to content

Commit 5f41b6d

Browse files
authored
Merge pull request github#18141 from tamasvajk/fix/db-quality-query
C#: Exclude `get`-only property accesses from `CallTargetStats`
2 parents 418ab4b + 7acbf1a commit 5f41b6d

File tree

7 files changed

+115
-6
lines changed

7 files changed

+115
-6
lines changed

csharp/ql/src/Telemetry/DatabaseQuality.qll

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,61 @@ module ReportStats<StatsSig Stats> {
3535
module CallTargetStats implements StatsSig {
3636
int getNumberOfOk() { result = count(Call c | exists(c.getTarget())) }
3737

38-
int getNumberOfNotOk() {
39-
result =
40-
count(Call c |
41-
not exists(c.getTarget()) and
42-
not c instanceof DelegateCall and
43-
not c instanceof DynamicExpr
38+
private predicate isNoSetterPropertyCallInConstructor(PropertyCall c) {
39+
exists(Property p, Constructor ctor |
40+
p = c.getProperty() and
41+
not exists(Setter a | a = p.getAnAccessor()) and
42+
c.getEnclosingCallable() = ctor and
43+
(
44+
c.hasThisQualifier()
45+
or
46+
ctor instanceof StaticConstructor and p.getDeclaringType() = ctor.getDeclaringType()
4447
)
48+
)
4549
}
4650

51+
private predicate isNoSetterPropertyInitialization(PropertyCall c) {
52+
exists(Property p, AssignExpr assign |
53+
p = c.getProperty() and
54+
not exists(Setter a | a = p.getAnAccessor()) and
55+
assign = c.getParent() and
56+
assign.getLValue() = c and
57+
assign.getParent() instanceof Property
58+
)
59+
}
60+
61+
private predicate isAnonymousObjectMemberDeclaration(PropertyCall c) {
62+
exists(Property p, AssignExpr assign |
63+
p = c.getProperty() and
64+
assign = c.getParent() and
65+
assign.getLValue() = c and
66+
assign.getParent() instanceof ObjectInitializer and
67+
assign.getParent().getParent() instanceof AnonymousObjectCreation
68+
)
69+
}
70+
71+
private predicate isInitializedWithCollectionInitializer(PropertyCall c) {
72+
exists(Property p, AssignExpr assign |
73+
p = c.getProperty() and
74+
assign = c.getParent() and
75+
assign.getLValue() = c and
76+
assign.getRValue() instanceof CollectionInitializer
77+
)
78+
}
79+
80+
additional predicate isNotOkCall(Call c) {
81+
not exists(c.getTarget()) and
82+
not c instanceof DelegateCall and
83+
not c instanceof DynamicExpr and
84+
not isNoSetterPropertyCallInConstructor(c) and
85+
not isNoSetterPropertyInitialization(c) and
86+
not isAnonymousObjectMemberDeclaration(c) and
87+
not isInitializedWithCollectionInitializer(c) and
88+
not c.getParent+() instanceof NameOfExpr
89+
}
90+
91+
int getNumberOfNotOk() { result = count(Call c | isNotOkCall(c)) }
92+
4793
string getOkText() { result = "calls with call target" }
4894

4995
string getNotOkText() { result = "calls with missing call target" }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* `csharp/diagnostic/database-quality` has been changed to exclude various property access expressions from database quality evaluation. The excluded property access expressions are expected to have no target callables even in manual or autobuilt databases.

csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected

Whitespace-only changes.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @id test/missing-call-target
3+
* @kind problem
4+
* @problem.severity warning
5+
*/
6+
7+
import csharp
8+
import Telemetry.DatabaseQuality
9+
10+
from Call call
11+
where CallTargetStats::isNotOkCall(call)
12+
select call, "Call without target $@.", call, call.toString()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
| Quality.cs:8:9:8:19 | access to property MyProperty5 | Call without target $@. | Quality.cs:8:9:8:19 | access to property MyProperty5 | access to property MyProperty5 |
2+
| Quality.cs:13:9:13:19 | access to property MyProperty1 | Call without target $@. | Quality.cs:13:9:13:19 | access to property MyProperty1 | access to property MyProperty1 |
3+
| Quality.cs:14:24:14:34 | access to property MyProperty3 | Call without target $@. | Quality.cs:14:24:14:34 | access to property MyProperty3 | access to property MyProperty3 |
4+
| 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 |
5+
| 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 |
6+
| 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 |
7+
| 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 |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @id test/missing-call-target
3+
* @kind problem
4+
* @problem.severity warning
5+
*/
6+
7+
import csharp
8+
import Telemetry.DatabaseQuality
9+
10+
from Call call
11+
where not exists(call.getTarget())
12+
select call, "Call without target $@.", call, call.toString()
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
public class Test
5+
{
6+
static Test()
7+
{
8+
MyProperty5 = 42;
9+
}
10+
11+
public Test()
12+
{
13+
MyProperty1 = 42;
14+
var x = nameof(MyProperty3);
15+
var y = nameof(MyProperty3.MyProperty2);
16+
17+
new Test()
18+
{
19+
MyProperty4 = { 1, 2, 3 }
20+
};
21+
}
22+
23+
public int MyProperty1 { get; }
24+
public int MyProperty2 { get; } = 42;
25+
public Test MyProperty3 { get; set; }
26+
public List<int> MyProperty4 { get; }
27+
static int MyProperty5 { get; }
28+
}

0 commit comments

Comments
 (0)