Skip to content

Commit d2f8b0b

Browse files
committed
C#: Handle constructors with member initializers and base() calls in CFG
1 parent e6ba282 commit d2f8b0b

File tree

13 files changed

+380
-72
lines changed

13 files changed

+380
-72
lines changed

csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,11 +1754,22 @@ module ControlFlow {
17541754
cfe = last(result.(JumpStmt).getChild(0), c) and
17551755
c instanceof NormalCompletion
17561756
or
1757-
// Flow from constructor initializer to first element of constructor body
1758-
cfe = any(ConstructorInitializer ci |
1759-
c instanceof SimpleCompletion and
1760-
result = first(ci.getConstructor().getBody())
1757+
exists(ConstructorInitializer ci, Constructor con |
1758+
cfe = last(ci, c) and
1759+
con = ci.getConstructor() and
1760+
c instanceof NormalCompletion
1761+
|
1762+
// Flow from constructor initializer to first member initializer
1763+
exists(InitializerSplitting::InitializedInstanceMember m |
1764+
InitializerSplitting::constructorInitializeOrder(con, m, 0)
1765+
|
1766+
result = first(m.getInitializer())
17611767
)
1768+
or
1769+
// Flow from constructor initializer to first element of constructor body
1770+
not InitializerSplitting::constructorInitializeOrder(con, _, _) and
1771+
result = first(con.getBody())
1772+
)
17621773
or
17631774
exists(Constructor con, InitializerSplitting::InitializedInstanceMember m, int i |
17641775
cfe = last(m.getInitializer(), c) and

csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,7 @@ module InitializerSplitting {
210210

211211
InitializedInstanceMember() {
212212
not this.isStatic() and
213-
if this instanceof Property
214-
then expr_parent_top_level_adjusted(ae, 1, this)
215-
else expr_parent_top_level_adjusted(ae, 0, this)
213+
expr_parent_top_level_adjusted(ae, _, this)
216214
}
217215

218216
/** Gets the initializer expression. */
@@ -235,9 +233,16 @@ module InitializerSplitting {
235233
*/
236234
predicate constructorInitializes(Constructor c, InitializedInstanceMember m) {
237235
c = c.getSourceDeclaration() and
238-
not c.hasInitializer() and
239236
not c.isStatic() and
240-
c.getDeclaringType().hasMember(m)
237+
c.getDeclaringType().hasMember(m) and
238+
(
239+
not c.hasInitializer()
240+
or
241+
// Members belonging to the base class are initialized via calls to the
242+
// base constructor
243+
c.getInitializer().isBase() and
244+
m.getDeclaringType() = c.getDeclaringType()
245+
)
241246
}
242247

243248
/**
@@ -337,7 +342,12 @@ module InitializerSplitting {
337342
override InitializerSplitKind getKind() { any() }
338343

339344
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
340-
none()
345+
exists(ConstructorInitializer ci |
346+
pred = last(ci, c) and
347+
succ = succ(pred, c) and
348+
succ = any(InitializedInstanceMember m).getAnInitializerDescendant() and
349+
this.getConstructor() = ci.getConstructor()
350+
)
341351
}
342352

343353
override predicate hasEntry(Callable c, ControlFlowElement succ) {
@@ -362,7 +372,8 @@ module InitializerSplitting {
362372
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
363373
this.appliesTo(pred) and
364374
succ = succ(pred, c) and
365-
succ = any(InitializedInstanceMember m).getAnInitializerDescendant()
375+
succ = any(InitializedInstanceMember m | constructorInitializes(this.getConstructor(), m))
376+
.getAnInitializerDescendant()
366377
}
367378
}
368379
}

csharp/ql/src/semmle/code/csharp/exprs/Call.qll

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -385,14 +385,16 @@ class VirtualMethodCall extends MethodCall {
385385
* `this(0)` (line 8) in
386386
*
387387
* ```
388-
* class A {
389-
* public A() { }
388+
* class A
389+
* {
390+
* public A() { }
390391
* }
391392
*
392-
* class B : A {
393-
* public B(int x) : base() { }
393+
* class B : A
394+
* {
395+
* public B(int x) : base() { }
394396
*
395-
* public B() : this(0) { }
397+
* public B() : this(0) { }
396398
* }
397399
* ```
398400
*/
@@ -403,19 +405,64 @@ class ConstructorInitializer extends Call, @constructor_init_expr {
403405

404406
override string toString() { result = "call to constructor " + this.getTarget().getName() }
405407

408+
private ValueOrRefType getTargetType() {
409+
result = this.getTarget().getDeclaringType().getSourceDeclaration()
410+
}
411+
412+
private ValueOrRefType getConstructorType() {
413+
result = this.getConstructor().getDeclaringType().getSourceDeclaration()
414+
}
415+
416+
/**
417+
* Holds if this initialier is a `this` initializer, for example `this(0)`
418+
* in
419+
*
420+
* ```
421+
* class A
422+
* {
423+
* A(int i) { }
424+
* A() : this(0) { }
425+
* }
426+
* ```
427+
*/
428+
predicate isThis() {
429+
this.getTargetType() = this.getConstructorType()
430+
}
431+
432+
/**
433+
* Holds if this initialier is a `base` initializer, for example `base(0)`
434+
* in
435+
*
436+
* ```
437+
* class A
438+
* {
439+
* A(int i) { }
440+
* }
441+
*
442+
* class B : A
443+
* {
444+
* B() : base(0) { }
445+
* }
446+
* ```
447+
*/
448+
predicate isBase() {
449+
this.getTargetType() != this.getConstructorType()
450+
}
451+
406452
/**
407453
* Gets the constructor that this initializer call belongs to. For example,
408454
* the initializer call `base()` on line 7 belongs to the constructor `B`
409455
* on line 6 in
410456
*
411457
* ```
412-
* class A {
413-
* public A() { }
458+
* class A
459+
* {
460+
* public A() { }
414461
* }
415462
*
416-
* class B : A {
417-
* public B()
418-
* : base() { }
463+
* class B : A
464+
* {
465+
* public B() : base() { }
419466
* }
420467
* ```
421468
*/

csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@
282282
| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | exit M | 20 |
283283
| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:16:16:20 | ... = ... | 2 |
284284
| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | exit NoConstructor | 8 |
285+
| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | exit Sub | 11 |
286+
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 8 |
287+
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 18 |
285288
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i | 3 |
286289
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | exit M1 | 1 |
287290
| NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:28:3:28 | 0 | 1 |

csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,9 @@
569569
| post | Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | enter M |
570570
| post | Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 |
571571
| post | Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | enter NoConstructor |
572+
| post | Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | enter Sub |
573+
| post | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | enter Sub |
574+
| post | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | enter Sub |
572575
| post | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
573576
| post | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
574577
| post | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | exit M1 |
@@ -2116,6 +2119,9 @@
21162119
| pre | Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | enter M |
21172120
| pre | Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 |
21182121
| pre | Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | enter NoConstructor |
2122+
| pre | Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | enter Sub |
2123+
| pre | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | enter Sub |
2124+
| pre | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | enter Sub |
21192125
| pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
21202126
| pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | exit M1 |
21212127
| pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:28:3:28 | 0 |

csharp/ql/test/library-tests/controlflow/graph/Dominance.expected

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,13 +1249,47 @@
12491249
| post | Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:59:13:60 | "" |
12501250
| post | Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:39:13:39 | access to local variable i |
12511251
| post | Initializers.cs:16:16:16:20 | ... = ... | Initializers.cs:16:20:16:20 | 1 |
1252-
| post | Initializers.cs:18:11:18:23 | exit NoConstructor | Initializers.cs:21:13:21:17 | ... = ... |
1253-
| post | Initializers.cs:20:13:20:13 | this access | Initializers.cs:18:11:18:23 | enter NoConstructor |
1254-
| post | Initializers.cs:20:13:20:17 | ... = ... | Initializers.cs:20:17:20:17 | 0 |
1255-
| post | Initializers.cs:20:17:20:17 | 0 | Initializers.cs:20:13:20:13 | this access |
1256-
| post | Initializers.cs:21:13:21:13 | this access | Initializers.cs:20:13:20:17 | ... = ... |
1257-
| post | Initializers.cs:21:13:21:17 | ... = ... | Initializers.cs:21:17:21:17 | 1 |
1258-
| post | Initializers.cs:21:17:21:17 | 1 | Initializers.cs:21:13:21:13 | this access |
1252+
| post | Initializers.cs:18:11:18:23 | exit NoConstructor | Initializers.cs:21:23:21:27 | ... = ... |
1253+
| post | Initializers.cs:20:23:20:23 | this access | Initializers.cs:18:11:18:23 | enter NoConstructor |
1254+
| post | Initializers.cs:20:23:20:23 | this access | Initializers.cs:33:9:33:11 | enter Sub |
1255+
| post | Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:27:20:27 | 0 |
1256+
| post | Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:27:20:27 | 0 |
1257+
| post | Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:23 | this access |
1258+
| post | Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:23 | this access |
1259+
| post | Initializers.cs:21:23:21:23 | this access | Initializers.cs:20:23:20:27 | ... = ... |
1260+
| post | Initializers.cs:21:23:21:23 | this access | Initializers.cs:20:23:20:27 | ... = ... |
1261+
| post | Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:27:21:27 | 1 |
1262+
| post | Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:27:21:27 | 1 |
1263+
| post | Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:23 | this access |
1264+
| post | Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:23 | this access |
1265+
| post | Initializers.cs:26:13:26:13 | this access | Initializers.cs:21:23:21:27 | ... = ... |
1266+
| post | Initializers.cs:26:13:26:13 | this access | Initializers.cs:29:17:29:20 | call to constructor NoConstructor |
1267+
| post | Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:17:26:17 | 2 |
1268+
| post | Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:17:26:17 | 2 |
1269+
| post | Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:13 | this access |
1270+
| post | Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:13 | this access |
1271+
| post | Initializers.cs:29:9:29:11 | exit Sub | Initializers.cs:29:26:29:30 | ... = ... |
1272+
| post | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:9:29:11 | enter Sub |
1273+
| post | Initializers.cs:29:24:29:33 | {...} | Initializers.cs:26:13:26:17 | ... = ... |
1274+
| post | Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:26:29:31 | ...; |
1275+
| post | Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:30:29:30 | 3 |
1276+
| post | Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:24:29:33 | {...} |
1277+
| post | Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:26:29:26 | this access |
1278+
| post | Initializers.cs:31:9:31:11 | exit Sub | Initializers.cs:31:31:31:35 | ... = ... |
1279+
| post | Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:9:31:11 | enter Sub |
1280+
| post | Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:22:31:25 | call to constructor Sub |
1281+
| post | Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:31:31:36 | ...; |
1282+
| post | Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:35:31:35 | access to parameter i |
1283+
| post | Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:29:31:38 | {...} |
1284+
| post | Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:31:31:31 | this access |
1285+
| post | Initializers.cs:33:9:33:11 | exit Sub | Initializers.cs:33:29:33:37 | ... = ... |
1286+
| post | Initializers.cs:33:27:33:40 | {...} | Initializers.cs:26:13:26:17 | ... = ... |
1287+
| post | Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:29:33:38 | ...; |
1288+
| post | Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:33:33:37 | ... + ... |
1289+
| post | Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:27:33:40 | {...} |
1290+
| post | Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:29:33:29 | this access |
1291+
| post | Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:37:33:37 | access to parameter j |
1292+
| post | Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:33 | access to parameter i |
12591293
| post | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i |
12601294
| post | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:28:3:28 | 0 |
12611295
| post | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:28 | ... ?? ... |
@@ -3810,13 +3844,47 @@
38103844
| pre | Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:37:13:63 | { ..., ... } |
38113845
| pre | Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:42:13:61 | object creation of type Initializers |
38123846
| pre | Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:16:16:20 | ... = ... |
3813-
| pre | Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:20:13:20:13 | this access |
3814-
| pre | Initializers.cs:20:13:20:13 | this access | Initializers.cs:20:17:20:17 | 0 |
3815-
| pre | Initializers.cs:20:13:20:17 | ... = ... | Initializers.cs:21:13:21:13 | this access |
3816-
| pre | Initializers.cs:20:17:20:17 | 0 | Initializers.cs:20:13:20:17 | ... = ... |
3817-
| pre | Initializers.cs:21:13:21:13 | this access | Initializers.cs:21:17:21:17 | 1 |
3818-
| pre | Initializers.cs:21:13:21:17 | ... = ... | Initializers.cs:18:11:18:23 | exit NoConstructor |
3819-
| pre | Initializers.cs:21:17:21:17 | 1 | Initializers.cs:21:13:21:17 | ... = ... |
3847+
| pre | Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:20:23:20:23 | this access |
3848+
| pre | Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 |
3849+
| pre | Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 |
3850+
| pre | Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access |
3851+
| pre | Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access |
3852+
| pre | Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... |
3853+
| pre | Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... |
3854+
| pre | Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 |
3855+
| pre | Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 |
3856+
| pre | Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:18:11:18:23 | exit NoConstructor |
3857+
| pre | Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:26:13:26:13 | this access |
3858+
| pre | Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... |
3859+
| pre | Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... |
3860+
| pre | Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 |
3861+
| pre | Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 |
3862+
| pre | Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:29:24:29:33 | {...} |
3863+
| pre | Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:33:27:33:40 | {...} |
3864+
| pre | Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... |
3865+
| pre | Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... |
3866+
| pre | Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:17:29:20 | call to constructor NoConstructor |
3867+
| pre | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:26:13:26:13 | this access |
3868+
| pre | Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:26:29:31 | ...; |
3869+
| pre | Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:30:29:30 | 3 |
3870+
| pre | Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:9:29:11 | exit Sub |
3871+
| pre | Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:26 | this access |
3872+
| pre | Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:26:29:30 | ... = ... |
3873+
| pre | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:22:31:25 | call to constructor Sub |
3874+
| pre | Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:29:31:38 | {...} |
3875+
| pre | Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:31:31:36 | ...; |
3876+
| pre | Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:35:31:35 | access to parameter i |
3877+
| pre | Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub |
3878+
| pre | Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:31 | this access |
3879+
| pre | Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:31:31:35 | ... = ... |
3880+
| pre | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:20:23:20:23 | this access |
3881+
| pre | Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:29:33:38 | ...; |
3882+
| pre | Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:33:33:33 | access to parameter i |
3883+
| pre | Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub |
3884+
| pre | Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:29 | this access |
3885+
| pre | Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:37:33:37 | access to parameter j |
3886+
| pre | Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:29:33:37 | ... = ... |
3887+
| pre | Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:37 | ... + ... |
38203888
| pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... |
38213889
| pre | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | exit M1 |
38223890
| pre | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:28:3:28 | 0 |

0 commit comments

Comments
 (0)