Skip to content

Commit ee62522

Browse files
committed
C#: Extract implicit constructor initializer calls
1 parent 6693c5b commit ee62522

File tree

7 files changed

+158
-65
lines changed

7 files changed

+158
-65
lines changed

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/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/dataflow/global/GetAnOutNode.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,9 @@
167167
| Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | normal | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check |
168168
| Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | normal | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check |
169169
| Splitting.cs:34:13:34:20 | dynamic call to method Check | normal | Splitting.cs:34:13:34:20 | dynamic call to method Check |
170+
| This.cs:7:5:7:8 | call to constructor Object | normal | This.cs:7:5:7:8 | call to constructor Object |
170171
| This.cs:17:9:17:18 | object creation of type This | normal | This.cs:17:9:17:18 | object creation of type This |
172+
| This.cs:22:9:22:11 | call to constructor This | normal | This.cs:22:9:22:11 | call to constructor This |
171173
| This.cs:28:13:28:21 | object creation of type Sub | normal | This.cs:28:13:28:21 | object creation of type Sub |
172174
| file://:0:0:0:0 | [summary] call to collectionSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany |
173175
| file://:0:0:0:0 | [summary] call to collectionSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| expressions.cs:56:9:56:13 | Class | expressions.cs:56:19:56:22 | call to constructor Class | expressions.cs:58:19:58:23 | Class |
2+
| expressions.cs:58:19:58:23 | Class | expressions.cs:58:19:58:23 | call to constructor Object | file://:0:0:0:0 | Object |
3+
| expressions.cs:132:13:132:18 | Nested | expressions.cs:132:13:132:18 | call to constructor Class | expressions.cs:56:9:56:13 | Class |
4+
| expressions.cs:133:13:133:18 | Nested | expressions.cs:133:29:133:32 | call to constructor Class | expressions.cs:58:19:58:23 | Class |
5+
| expressions.cs:249:16:249:26 | LoginDialog | expressions.cs:249:16:249:26 | call to constructor Object | file://:0:0:0:0 | Object |
6+
| expressions.cs:270:16:270:24 | IntVector | expressions.cs:270:16:270:24 | call to constructor Object | file://:0:0:0:0 | Object |
7+
| expressions.cs:310:16:310:20 | Digit | expressions.cs:310:16:310:20 | call to constructor ValueType | file://:0:0:0:0 | ValueType |
8+
| expressions.cs:480:20:480:22 | Num | expressions.cs:480:20:480:22 | call to constructor Object | file://:0:0:0:0 | Object |
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import csharp
2+
3+
private class ConstructorInitializerTarget extends Constructor {
4+
override predicate hasLocationInfo(
5+
string filepath, int startline, int startcolumn, int endline, int endcolumn
6+
) {
7+
if this.fromSource()
8+
then this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
9+
else (
10+
filepath = "" and
11+
startline = 0 and
12+
startcolumn = 0 and
13+
endline = 0 and
14+
endcolumn = 0
15+
)
16+
}
17+
}
18+
19+
from Constructor c, ConstructorInitializer i, ConstructorInitializerTarget target
20+
where c.getInitializer() = i and target = i.getTarget()
21+
select c, i, target

csharp/ql/test/library-tests/expressions/PrintAst.expected

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,14 @@ expressions.cs:
835835
# 129| 21: [Class] Nested
836836
#-----| 3: (Base types)
837837
# 129| 0: [TypeMention] Class
838-
# 133| 4: [InstanceConstructor] Nested
838+
# 131| 4: [StaticConstructor] Nested
839+
# 131| 4: [BlockStmt] {...}
840+
# 132| 5: [InstanceConstructor] Nested
841+
#-----| 2: (Parameters)
842+
# 132| 0: [Parameter] b
843+
# 132| -1: [TypeMention] bool
844+
# 132| 4: [BlockStmt] {...}
845+
# 133| 6: [InstanceConstructor] Nested
839846
#-----| 2: (Parameters)
840847
# 133| 0: [Parameter] i
841848
# 133| -1: [TypeMention] int
@@ -844,7 +851,7 @@ expressions.cs:
844851
# 133| 0: [ParameterAccess] access to parameter i
845852
# 133| 1: [IntLiteral] 1
846853
# 133| 4: [BlockStmt] {...}
847-
# 135| 5: [Method] OtherAccesses
854+
# 135| 7: [Method] OtherAccesses
848855
# 135| -1: [TypeMention] Void
849856
# 136| 4: [BlockStmt] {...}
850857
# 137| 0: [ExprStmt] ...;

csharp/ql/test/library-tests/expressions/expressions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ public static void PrintTypes()
128128

129129
class Nested : Class
130130
{
131-
132-
131+
static Nested() { }
132+
Nested(bool b) { }
133133
Nested(int i) : base(i + 1) { }
134134

135135
void OtherAccesses()

0 commit comments

Comments
 (0)