Skip to content

Commit 5d14093

Browse files
committed
C#: Add field initializers to CFG for constructors
This commit adds field initializers to the CFG for non-static constructors. For example, in ``` class C { int Field1 = 0; int Field2 = Field1 + 1; int Field3; public C() { Field3 = 2; } public C(int i) { Field3 = 3; } } ``` the initializer expressions `Field1 = 0` and `Field2 = Field1 + 1` are added to the two constructors, mimicking ``` public C() { Field1 = 0; Field2 = Field1 + 1; Field3 = 2; } ``` and ``` public C() { Field1 = 0; Field2 = Field1 + 1; Field3 = 3; } ``` respectively. This means that we no longer have to synthesize calls, callables, parameters, and arguments in the data flow library, so much of the work from d175550 can be simplified.
1 parent eb97d7b commit 5d14093

21 files changed

+4061
-466
lines changed

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class BasicBlock extends TBasicBlockStart {
7575
ControlFlow::Node getLastNode() { result = getNode(length() - 1) }
7676

7777
/** Gets the callable that this basic block belongs to. */
78-
Callable getCallable() { result = this.getAPredecessor().getCallable() }
78+
final Callable getCallable() { result = this.getFirstNode().getEnclosingCallable() }
7979

8080
/** Gets the length of this basic block. */
8181
int length() { result = strictcount(getANode()) }
@@ -346,8 +346,6 @@ private import Internal
346346
*/
347347
class EntryBasicBlock extends BasicBlock {
348348
EntryBasicBlock() { entryBB(this) }
349-
350-
override Callable getCallable() { result.getEntryPoint() = this.getFirstNode() }
351349
}
352350

353351
/** Holds if `bb` is an entry basic block. */

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

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,11 @@ module ControlFlow {
287287

288288
ElementNode() { this = TElementNode(cfe, splits) }
289289

290-
override Callable getEnclosingCallable() { result = cfe.getEnclosingCallable() }
290+
override Callable getEnclosingCallable() {
291+
result = cfe.getEnclosingCallable()
292+
or
293+
result = this.getASplit().(InitializerSplitting::InitializerSplitImpl).getConstructor()
294+
}
291295

292296
override ControlFlowElement getElement() { result = cfe }
293297

@@ -1756,6 +1760,22 @@ module ControlFlow {
17561760
result = first(ci.getConstructor().getBody())
17571761
)
17581762
or
1763+
exists(Constructor con, InitializerSplitting::InitializedInstanceMember m, int i |
1764+
cfe = last(m.getInitializer(), c) and
1765+
c instanceof NormalCompletion and
1766+
InitializerSplitting::constructorInitializeOrder(con, m, i)
1767+
|
1768+
// Flow from one member initializer to the next
1769+
exists(InitializerSplitting::InitializedInstanceMember next |
1770+
InitializerSplitting::constructorInitializeOrder(con, next, i + 1) and
1771+
result = first(next.getInitializer())
1772+
)
1773+
or
1774+
// Flow from last member initializer to constructor body
1775+
m = InitializerSplitting::lastConstructorInitializer(con) and
1776+
result = first(con.getBody())
1777+
)
1778+
or
17591779
// Flow from element with `goto` completion to first element of relevant
17601780
// target
17611781
c = any(GotoCompletion gc |
@@ -1831,11 +1851,18 @@ module ControlFlow {
18311851
p = any(Callable c |
18321852
if exists(c.(Constructor).getInitializer())
18331853
then result = first(c.(Constructor).getInitializer())
1834-
else result = first(c.getBody())
1854+
else
1855+
if InitializerSplitting::constructorInitializes(c, _)
1856+
then
1857+
result = first(any(InitializerSplitting::InitializedInstanceMember m |
1858+
InitializerSplitting::constructorInitializeOrder(c, m, 0)
1859+
).getInitializer())
1860+
else result = first(c.getBody())
18351861
)
18361862
or
18371863
expr_parent_top_level_adjusted(any(Expr e | result = first(e)), _, p) and
1838-
not p instanceof Callable
1864+
not p instanceof Callable and
1865+
not p instanceof InitializerSplitting::InitializedInstanceMember
18391866
}
18401867

18411868
/**
@@ -1845,6 +1872,12 @@ module ControlFlow {
18451872
Callable succExit(ControlFlowElement cfe, Completion c) {
18461873
cfe = last(result.getBody(), c) and
18471874
not c instanceof GotoCompletion
1875+
or
1876+
exists(InitializerSplitting::InitializedInstanceMember m |
1877+
m = InitializerSplitting::lastConstructorInitializer(result) and
1878+
cfe = last(m.getInitializer(), c) and
1879+
not result.hasBody()
1880+
)
18481881
}
18491882
}
18501883
import Successor

0 commit comments

Comments
 (0)