Skip to content

Commit bb1cb73

Browse files
authored
Merge pull request github#5795 from hvitved/csharp/implicit-constructor-inits
C#: Extract implicit constructor initializer calls
2 parents c05ef12 + b77b3da commit bb1cb73

File tree

17 files changed

+274
-137
lines changed

17 files changed

+274
-137
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
lgtm,codescanning
2+
* Implicit base constructor calls are now extracted. For example, in
3+
```csharp
4+
class Base
5+
{
6+
public Base() { }
7+
}
8+
9+
class Sub : Base
10+
{
11+
public Sub() { }
12+
}
13+
```
14+
there is an implicit call to the `Base` constructor from the `Sub` constructor.

csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,38 @@ protected override void ExtractInitializers(TextWriter trapFile)
4141
var initializer = syntax?.Initializer;
4242

4343
if (initializer is null)
44+
{
45+
if (Symbol.MethodKind is MethodKind.Constructor)
46+
{
47+
var baseType = Symbol.ContainingType.BaseType;
48+
if (baseType is null)
49+
{
50+
Context.ModelError(Symbol, "Unable to resolve base type in implicit constructor initializer");
51+
return;
52+
}
53+
54+
var baseConstructor = baseType.InstanceConstructors.FirstOrDefault(c => c.Arity is 0);
55+
56+
if (baseConstructor is null)
57+
{
58+
Context.ModelError(Symbol, "Unable to resolve implicit constructor initializer call");
59+
return;
60+
}
61+
62+
var baseConstructorTarget = Create(Context, baseConstructor);
63+
var info = new ExpressionInfo(Context,
64+
AnnotatedTypeSymbol.CreateNotAnnotated(baseType),
65+
Location,
66+
Kinds.ExprKind.CONSTRUCTOR_INIT,
67+
this,
68+
-1,
69+
isCompilerGenerated: true,
70+
null);
71+
72+
trapFile.expr_call(new Expression(info), baseConstructorTarget);
73+
}
4474
return;
75+
}
4576

4677
ITypeSymbol initializerType;
4778
var symbolInfo = Context.GetSymbolInfo(initializer);

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

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -244,18 +244,10 @@ module InitializerSplitting {
244244
* Holds if `c` is a non-static constructor that performs the initialization
245245
* of member `m`.
246246
*/
247-
predicate constructorInitializes(Constructor c, InitializedInstanceMember m) {
247+
predicate constructorInitializes(InstanceConstructor c, InitializedInstanceMember m) {
248248
c.isUnboundDeclaration() and
249-
not c.isStatic() and
250-
c.getDeclaringType().hasMember(m) and
251-
(
252-
not c.hasInitializer()
253-
or
254-
// Members belonging to the base class are initialized via calls to the
255-
// base constructor
256-
c.getInitializer().isBase() and
257-
m.getDeclaringType() = c.getDeclaringType()
258-
)
249+
c.getDeclaringType().getAMember() = m and
250+
not c.getInitializer().isThis()
259251
}
260252

261253
/**

csharp/ql/test/experimental/ir/ir/raw_ir.expected

Lines changed: 85 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -285,29 +285,37 @@ collections.cs:
285285
constructor_init.cs:
286286
# 5| System.Void BaseClass..ctor()
287287
# 5| Block 0
288-
# 5| v5_1(Void) = EnterFunction :
289-
# 5| mu5_2(<unknown>) = AliasedDefinition :
290-
# 5| r5_3(glval<BaseClass>) = InitializeThis :
291-
# 6| v6_1(Void) = NoOp :
292-
# 5| v5_4(Void) = ReturnVoid :
293-
# 5| v5_5(Void) = AliasedUse : ~m?
294-
# 5| v5_6(Void) = ExitFunction :
288+
# 5| v5_1(Void) = EnterFunction :
289+
# 5| mu5_2(<unknown>) = AliasedDefinition :
290+
# 5| r5_3(glval<BaseClass>) = InitializeThis :
291+
# 5| r5_4(glval<Object>) = Convert[BaseClass : Object] : r5_3
292+
# 5| r5_5(<funcaddr>) = FunctionAddress[Object] :
293+
# 5| v5_6(Void) = Call[Object] : func:r5_5, this:r5_4
294+
# 5| mu5_7(<unknown>) = ^CallSideEffect : ~m?
295+
# 6| v6_1(Void) = NoOp :
296+
# 5| v5_8(Void) = ReturnVoid :
297+
# 5| v5_9(Void) = AliasedUse : ~m?
298+
# 5| v5_10(Void) = ExitFunction :
295299

296300
# 9| System.Void BaseClass..ctor(System.Int32)
297301
# 9| Block 0
298-
# 9| v9_1(Void) = EnterFunction :
299-
# 9| mu9_2(<unknown>) = AliasedDefinition :
300-
# 9| r9_3(glval<BaseClass>) = InitializeThis :
301-
# 9| r9_4(glval<Int32>) = VariableAddress[i] :
302-
# 9| mu9_5(Int32) = InitializeParameter[i] : &:r9_4
303-
# 11| r11_1(glval<Int32>) = VariableAddress[i] :
304-
# 11| r11_2(Int32) = Load[i] : &:r11_1, ~m?
305-
# 11| r11_3(BaseClass) = CopyValue : r9_3
306-
# 11| r11_4(glval<Int32>) = FieldAddress[num] : r11_3
307-
# 11| mu11_5(Int32) = Store[?] : &:r11_4, r11_2
308-
# 9| v9_6(Void) = ReturnVoid :
309-
# 9| v9_7(Void) = AliasedUse : ~m?
310-
# 9| v9_8(Void) = ExitFunction :
302+
# 9| v9_1(Void) = EnterFunction :
303+
# 9| mu9_2(<unknown>) = AliasedDefinition :
304+
# 9| r9_3(glval<BaseClass>) = InitializeThis :
305+
# 9| r9_4(glval<Int32>) = VariableAddress[i] :
306+
# 9| mu9_5(Int32) = InitializeParameter[i] : &:r9_4
307+
# 9| r9_6(glval<Object>) = Convert[BaseClass : Object] : r9_3
308+
# 9| r9_7(<funcaddr>) = FunctionAddress[Object] :
309+
# 9| v9_8(Void) = Call[Object] : func:r9_7, this:r9_6
310+
# 9| mu9_9(<unknown>) = ^CallSideEffect : ~m?
311+
# 11| r11_1(glval<Int32>) = VariableAddress[i] :
312+
# 11| r11_2(Int32) = Load[i] : &:r11_1, ~m?
313+
# 11| r11_3(BaseClass) = CopyValue : r9_3
314+
# 11| r11_4(glval<Int32>) = FieldAddress[num] : r11_3
315+
# 11| mu11_5(Int32) = Store[?] : &:r11_4, r11_2
316+
# 9| v9_10(Void) = ReturnVoid :
317+
# 9| v9_11(Void) = AliasedUse : ~m?
318+
# 9| v9_12(Void) = ExitFunction :
311319

312320
# 17| System.Void DerivedClass..ctor()
313321
# 17| Block 0
@@ -469,20 +477,24 @@ delegates.cs:
469477
events.cs:
470478
# 8| System.Void Events..ctor()
471479
# 8| Block 0
472-
# 8| v8_1(Void) = EnterFunction :
473-
# 8| mu8_2(<unknown>) = AliasedDefinition :
474-
# 8| r8_3(glval<Events>) = InitializeThis :
475-
# 10| r10_1(MyDel) = NewObj :
476-
# 10| r10_2(<funcaddr>) = FunctionAddress[MyDel] :
477-
# 10| r10_3(glval<MyDel>) = FunctionAddress[Fun] :
478-
# 10| v10_4(Void) = Call[MyDel] : func:r10_2, this:r10_1, 0:r10_3
479-
# 10| mu10_5(<unknown>) = ^CallSideEffect : ~m?
480-
# 10| r10_6(Events) = CopyValue : r8_3
481-
# 10| r10_7(glval<MyDel>) = FieldAddress[Inst] : r10_6
482-
# 10| mu10_8(MyDel) = Store[?] : &:r10_7, r10_1
483-
# 8| v8_4(Void) = ReturnVoid :
484-
# 8| v8_5(Void) = AliasedUse : ~m?
485-
# 8| v8_6(Void) = ExitFunction :
480+
# 8| v8_1(Void) = EnterFunction :
481+
# 8| mu8_2(<unknown>) = AliasedDefinition :
482+
# 8| r8_3(glval<Events>) = InitializeThis :
483+
# 8| r8_4(glval<Object>) = Convert[Events : Object] : r8_3
484+
# 8| r8_5(<funcaddr>) = FunctionAddress[Object] :
485+
# 8| v8_6(Void) = Call[Object] : func:r8_5, this:r8_4
486+
# 8| mu8_7(<unknown>) = ^CallSideEffect : ~m?
487+
# 10| r10_1(MyDel) = NewObj :
488+
# 10| r10_2(<funcaddr>) = FunctionAddress[MyDel] :
489+
# 10| r10_3(glval<MyDel>) = FunctionAddress[Fun] :
490+
# 10| v10_4(Void) = Call[MyDel] : func:r10_2, this:r10_1, 0:r10_3
491+
# 10| mu10_5(<unknown>) = ^CallSideEffect : ~m?
492+
# 10| r10_6(Events) = CopyValue : r8_3
493+
# 10| r10_7(glval<MyDel>) = FieldAddress[Inst] : r10_6
494+
# 10| mu10_8(MyDel) = Store[?] : &:r10_7, r10_1
495+
# 8| v8_8(Void) = ReturnVoid :
496+
# 8| v8_9(Void) = AliasedUse : ~m?
497+
# 8| v8_10(Void) = ExitFunction :
486498

487499
# 13| System.Void Events.AddEvent()
488500
# 13| Block 0
@@ -1237,29 +1249,37 @@ lock.cs:
12371249
obj_creation.cs:
12381250
# 7| System.Void ObjCreation.MyClass..ctor()
12391251
# 7| Block 0
1240-
# 7| v7_1(Void) = EnterFunction :
1241-
# 7| mu7_2(<unknown>) = AliasedDefinition :
1242-
# 7| r7_3(glval<MyClass>) = InitializeThis :
1243-
# 8| v8_1(Void) = NoOp :
1244-
# 7| v7_4(Void) = ReturnVoid :
1245-
# 7| v7_5(Void) = AliasedUse : ~m?
1246-
# 7| v7_6(Void) = ExitFunction :
1252+
# 7| v7_1(Void) = EnterFunction :
1253+
# 7| mu7_2(<unknown>) = AliasedDefinition :
1254+
# 7| r7_3(glval<MyClass>) = InitializeThis :
1255+
# 7| r7_4(glval<Object>) = Convert[MyClass : Object] : r7_3
1256+
# 7| r7_5(<funcaddr>) = FunctionAddress[Object] :
1257+
# 7| v7_6(Void) = Call[Object] : func:r7_5, this:r7_4
1258+
# 7| mu7_7(<unknown>) = ^CallSideEffect : ~m?
1259+
# 8| v8_1(Void) = NoOp :
1260+
# 7| v7_8(Void) = ReturnVoid :
1261+
# 7| v7_9(Void) = AliasedUse : ~m?
1262+
# 7| v7_10(Void) = ExitFunction :
12471263

12481264
# 11| System.Void ObjCreation.MyClass..ctor(System.Int32)
12491265
# 11| Block 0
1250-
# 11| v11_1(Void) = EnterFunction :
1251-
# 11| mu11_2(<unknown>) = AliasedDefinition :
1252-
# 11| r11_3(glval<MyClass>) = InitializeThis :
1253-
# 11| r11_4(glval<Int32>) = VariableAddress[_x] :
1254-
# 11| mu11_5(Int32) = InitializeParameter[_x] : &:r11_4
1255-
# 13| r13_1(glval<Int32>) = VariableAddress[_x] :
1256-
# 13| r13_2(Int32) = Load[_x] : &:r13_1, ~m?
1257-
# 13| r13_3(MyClass) = CopyValue : r11_3
1258-
# 13| r13_4(glval<Int32>) = FieldAddress[x] : r13_3
1259-
# 13| mu13_5(Int32) = Store[?] : &:r13_4, r13_2
1260-
# 11| v11_6(Void) = ReturnVoid :
1261-
# 11| v11_7(Void) = AliasedUse : ~m?
1262-
# 11| v11_8(Void) = ExitFunction :
1266+
# 11| v11_1(Void) = EnterFunction :
1267+
# 11| mu11_2(<unknown>) = AliasedDefinition :
1268+
# 11| r11_3(glval<MyClass>) = InitializeThis :
1269+
# 11| r11_4(glval<Int32>) = VariableAddress[_x] :
1270+
# 11| mu11_5(Int32) = InitializeParameter[_x] : &:r11_4
1271+
# 11| r11_6(glval<Object>) = Convert[MyClass : Object] : r11_3
1272+
# 11| r11_7(<funcaddr>) = FunctionAddress[Object] :
1273+
# 11| v11_8(Void) = Call[Object] : func:r11_7, this:r11_6
1274+
# 11| mu11_9(<unknown>) = ^CallSideEffect : ~m?
1275+
# 13| r13_1(glval<Int32>) = VariableAddress[_x] :
1276+
# 13| r13_2(Int32) = Load[_x] : &:r13_1, ~m?
1277+
# 13| r13_3(MyClass) = CopyValue : r11_3
1278+
# 13| r13_4(glval<Int32>) = FieldAddress[x] : r13_3
1279+
# 13| mu13_5(Int32) = Store[?] : &:r13_4, r13_2
1280+
# 11| v11_10(Void) = ReturnVoid :
1281+
# 11| v11_11(Void) = AliasedUse : ~m?
1282+
# 11| v11_12(Void) = ExitFunction :
12631283

12641284
# 17| System.Void ObjCreation.SomeFun(ObjCreation.MyClass)
12651285
# 17| Block 0
@@ -1884,13 +1904,17 @@ stmts.cs:
18841904
using.cs:
18851905
# 7| System.Void UsingStmt.MyDisposable..ctor()
18861906
# 7| Block 0
1887-
# 7| v7_1(Void) = EnterFunction :
1888-
# 7| mu7_2(<unknown>) = AliasedDefinition :
1889-
# 7| r7_3(glval<MyDisposable>) = InitializeThis :
1890-
# 7| v7_4(Void) = NoOp :
1891-
# 7| v7_5(Void) = ReturnVoid :
1892-
# 7| v7_6(Void) = AliasedUse : ~m?
1893-
# 7| v7_7(Void) = ExitFunction :
1907+
# 7| v7_1(Void) = EnterFunction :
1908+
# 7| mu7_2(<unknown>) = AliasedDefinition :
1909+
# 7| r7_3(glval<MyDisposable>) = InitializeThis :
1910+
# 7| r7_4(glval<Object>) = Convert[MyDisposable : Object] : r7_3
1911+
# 7| r7_5(<funcaddr>) = FunctionAddress[Object] :
1912+
# 7| v7_6(Void) = Call[Object] : func:r7_5, this:r7_4
1913+
# 7| mu7_7(<unknown>) = ^CallSideEffect : ~m?
1914+
# 7| v7_8(Void) = NoOp :
1915+
# 7| v7_9(Void) = ReturnVoid :
1916+
# 7| v7_10(Void) = AliasedUse : ~m?
1917+
# 7| v7_11(Void) = ExitFunction :
18941918

18951919
# 8| System.Void UsingStmt.MyDisposable.DoSomething()
18961920
# 8| Block 0

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -674,14 +674,14 @@
674674
| Foreach.cs:36:10:36:11 | exit M6 (normal) | Foreach.cs:36:10:36:11 | exit M6 | 2 |
675675
| Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | 1 |
676676
| Foreach.cs:38:26:38:26 | String x | Foreach.cs:39:11:39:11 | ; | 4 |
677-
| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | exit Initializers | 15 |
678-
| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | exit Initializers | 15 |
677+
| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | exit Initializers | 16 |
678+
| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | exit Initializers | 16 |
679679
| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | exit M | 22 |
680680
| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... | 2 |
681681
| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | exit NoConstructor | 9 |
682682
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 12 |
683683
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 9 |
684-
| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | exit Sub | 19 |
684+
| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | exit Sub | 14 |
685685
| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | exit Test | 105 |
686686
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:9:13:9:28 | ... == ... | 7 |
687687
| LoopUnrolling.cs:7:10:7:11 | exit M1 (normal) | LoopUnrolling.cs:7:10:7:11 | exit M1 | 2 |
@@ -776,6 +776,7 @@
776776
| MultiImplementationA.cs:16:17:16:18 | exit M1 (normal) | MultiImplementationB.cs:14:17:14:18 | exit M1 | 2 |
777777
| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:18:9:18:22 | M2(...) | 2 |
778778
| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:9:18:22 | exit M2 | 4 |
779+
| MultiImplementationA.cs:20:12:20:13 | call to constructor Object | MultiImplementationA.cs:20:12:20:13 | call to constructor Object | 1 |
779780
| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | 1 |
780781
| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | 1 |
781782
| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | 1 |
@@ -858,6 +859,7 @@
858859
| MultiImplementationB.cs:14:17:14:18 | exit M1 (normal) | MultiImplementationB.cs:14:17:14:18 | exit M1 | 2 |
859860
| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:16:9:16:31 | M2(...) | 2 |
860861
| MultiImplementationB.cs:16:9:16:31 | enter M2 | MultiImplementationB.cs:16:9:16:31 | exit M2 | 5 |
862+
| MultiImplementationB.cs:18:12:18:13 | call to constructor Object | MultiImplementationB.cs:18:12:18:13 | call to constructor Object | 1 |
861863
| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | 1 |
862864
| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | 1 |
863865
| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | 1 |
@@ -1231,7 +1233,7 @@
12311233
| cflow.cs:127:48:127:49 | "" | cflow.cs:127:48:127:49 | "" | 1 |
12321234
| cflow.cs:127:53:127:57 | this access | cflow.cs:127:53:127:57 | access to field Field | 2 |
12331235
| cflow.cs:127:62:127:64 | enter set_Prop | cflow.cs:127:62:127:64 | exit set_Prop | 8 |
1234-
| cflow.cs:129:5:129:15 | enter ControlFlow | cflow.cs:129:5:129:15 | exit ControlFlow | 8 |
1236+
| cflow.cs:129:5:129:15 | enter ControlFlow | cflow.cs:129:5:129:15 | exit ControlFlow | 9 |
12351237
| cflow.cs:134:5:134:15 | enter ControlFlow | cflow.cs:134:5:134:15 | exit ControlFlow | 9 |
12361238
| cflow.cs:136:12:136:22 | enter ControlFlow | cflow.cs:136:12:136:22 | exit ControlFlow | 8 |
12371239
| cflow.cs:138:40:138:40 | enter + | cflow.cs:138:40:138:40 | exit + | 9 |
@@ -1330,7 +1332,7 @@
13301332
| cflow.cs:284:5:284:18 | enter ControlFlowSub | cflow.cs:284:5:284:18 | exit ControlFlowSub | 5 |
13311333
| cflow.cs:286:5:286:18 | enter ControlFlowSub | cflow.cs:286:5:286:18 | exit ControlFlowSub | 7 |
13321334
| cflow.cs:291:12:291:12 | enter M | cflow.cs:291:12:291:12 | exit M | 6 |
1333-
| cflow.cs:296:5:296:25 | enter NegationInConstructor | cflow.cs:296:5:296:25 | exit NegationInConstructor | 4 |
1335+
| cflow.cs:296:5:296:25 | enter NegationInConstructor | cflow.cs:296:5:296:25 | exit NegationInConstructor | 5 |
13341336
| cflow.cs:298:10:298:10 | enter M | cflow.cs:300:46:300:50 | ... > ... | 7 |
13351337
| cflow.cs:300:44:300:51 | [false] !... | cflow.cs:300:44:300:51 | [false] !... | 1 |
13361338
| cflow.cs:300:44:300:51 | [true] !... | cflow.cs:300:44:300:51 | [true] !... | 1 |

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ multipleSuccessors
99
| MultiImplementationA.cs:13:16:13:20 | ... = ... | successor | MultiImplementationA.cs:24:16:24:16 | this access |
1010
| MultiImplementationA.cs:13:16:13:20 | ... = ... | successor | MultiImplementationB.cs:11:16:11:16 | this access |
1111
| MultiImplementationA.cs:13:16:13:20 | ... = ... | successor | MultiImplementationB.cs:22:16:22:16 | this access |
12+
| MultiImplementationA.cs:20:12:20:13 | call to constructor Object | successor | MultiImplementationA.cs:13:16:13:16 | this access |
13+
| MultiImplementationA.cs:20:12:20:13 | call to constructor Object | successor | MultiImplementationB.cs:11:16:11:16 | this access |
1214
| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | successor | MultiImplementationA.cs:21:27:21:29 | {...} |
1315
| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | successor | MultiImplementationB.cs:19:27:19:29 | {...} |
1416
| MultiImplementationA.cs:24:32:24:34 | ... = ... | successor | MultiImplementationA.cs:20:22:20:31 | {...} |
@@ -19,6 +21,8 @@ multipleSuccessors
1921
| MultiImplementationB.cs:11:16:11:20 | ... = ... | successor | MultiImplementationA.cs:24:16:24:16 | this access |
2022
| MultiImplementationB.cs:11:16:11:20 | ... = ... | successor | MultiImplementationB.cs:11:16:11:16 | this access |
2123
| MultiImplementationB.cs:11:16:11:20 | ... = ... | successor | MultiImplementationB.cs:22:16:22:16 | this access |
24+
| MultiImplementationB.cs:18:12:18:13 | call to constructor Object | successor | MultiImplementationA.cs:13:16:13:16 | this access |
25+
| MultiImplementationB.cs:18:12:18:13 | call to constructor Object | successor | MultiImplementationB.cs:11:16:11:16 | this access |
2226
| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | successor | MultiImplementationA.cs:21:27:21:29 | {...} |
2327
| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | successor | MultiImplementationB.cs:19:27:19:29 | {...} |
2428
| MultiImplementationB.cs:22:32:22:34 | ... = ... | successor | MultiImplementationA.cs:20:22:20:31 | {...} |

0 commit comments

Comments
 (0)