Skip to content

Commit e330d5a

Browse files
authored
Merge pull request #1549 from hvitved/csharp/cfg/loop-unrolling
C#: Loop unrolling for `foreach` statements
2 parents 10076a6 + 41cd13a commit e330d5a

34 files changed

+2618
-764
lines changed

change-notes/1.23/analysis-csharp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ The following changes in version 1.23 affect C# analysis in all applications.
3636
picture of the partial flow paths from a given source. The feature is
3737
disabled by default and can be enabled for individual configurations by
3838
overriding `int explorationLimit()`.
39+
* `foreach` statements where the body is guaranteed to be executed at least once, such as `foreach (var x in new string[]{ "a", "b", "c" }) { ... }`, are now recognized by all analyses based on the control flow graph (such as SSA, data flow and taint tracking).
3940

4041
## Changes to autobuilder

csharp/ql/src/semmle/code/csharp/Assignable.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ module AssignableDefinitions {
567567
* entry point of `p`'s callable to basic block `bb` without passing through
568568
* any assignments to `p`.
569569
*/
570+
pragma[nomagic]
570571
private predicate parameterReachesWithoutDef(Parameter p, ControlFlow::BasicBlock bb) {
571572
forall(AssignableDefinition def | basicBlockRefParamDef(bb, p, def) |
572573
isUncertainRefCall(def.getTargetAccess())

csharp/ql/src/semmle/code/csharp/Implements.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) {
6565
* `I.M()` is compatible with `A.M()` for types `A` and `B`, but not
6666
* for type `C`, because `C.M()` conflicts.
6767
*/
68+
pragma[nomagic]
6869
private Virtualizable getAnImplementedInterfaceMemberForSubType(Virtualizable m, ValueOrRefType t) {
6970
result = getACompatibleInterfaceMember(m) and
7071
t = m.getDeclaringType()
@@ -86,6 +87,7 @@ private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Virtu
8687
* signature, and where `m` can potentially be accessed when
8788
* the interface member is accessed.
8889
*/
90+
pragma[nomagic]
8991
private Virtualizable getACompatibleInterfaceMember(Virtualizable m) {
9092
result = getACompatibleInterfaceMemberAux(m) and
9193
(
@@ -97,12 +99,14 @@ private Virtualizable getACompatibleInterfaceMember(Virtualizable m) {
9799
)
98100
}
99101

102+
pragma[nomagic]
100103
private Virtualizable getACompatibleExplicitInterfaceMember(Virtualizable m, ValueOrRefType declType) {
101104
result = getACompatibleInterfaceMemberAux(m) and
102105
declType = m.getDeclaringType() and
103106
m.implementsExplicitInterface()
104107
}
105108

109+
pragma[nomagic]
106110
private Virtualizable getACompatibleInterfaceMemberAux(Virtualizable m) {
107111
result = getACompatibleInterfaceAccessor(m) or
108112
result = getACompatibleInterfaceIndexer(m) or

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
3232
* several `ControlFlow::Node`s, for example to represent the continuation
3333
* flow in a `try/catch/finally` construction.
3434
*/
35-
Node getAControlFlowNode() { result.getElement() = this }
35+
Nodes::ElementNode getAControlFlowNode() { result.getElement() = this }
3636

3737
/**
3838
* Gets a first control flow node executed within this element.
3939
*/
40-
Node getAControlFlowEntryNode() {
40+
Nodes::ElementNode getAControlFlowEntryNode() {
4141
result = Internal::getAControlFlowEntryNode(this).getAControlFlowNode()
4242
}
4343

4444
/**
4545
* Gets a potential last control flow node executed within this element.
4646
*/
47-
Node getAControlFlowExitNode() {
47+
Nodes::ElementNode getAControlFlowExitNode() {
4848
result = Internal::getAControlFlowExitNode(this).getAControlFlowNode()
4949
}
5050

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ module ControlFlow {
317317
class ExceptionHandlerSplit = ExceptionHandlerSplitting::ExceptionHandlerSplitImpl;
318318

319319
class BooleanSplit = BooleanSplitting::BooleanSplitImpl;
320+
321+
class LoopUnrollingSplit = LoopUnrollingSplitting::LoopUnrollingSplitImpl;
320322
}
321323

322324
class BasicBlock = BBs::BasicBlock;

0 commit comments

Comments
 (0)