Skip to content

Commit 1f4924f

Browse files
committed
Swift: Create a custom "AST" version of the public CFG classes. This is
necessary because the CFG library doesn't support the following two requirements simultaneously: 1. Traverse AST classes by virtual dispatch 2. Construct ControlFlowElements from non-AST classes Because the CFG trees derive from the a base type that must be a subtype of `ControlFlowElement`. So if we make `ControlFlowElement` an IPA type, we cannot write: ``` class AssignTree extends PostOrderTree instanceof AssignExpr { ... } ``` because `AssignExpr` is not a subtype of PostOrderTree (since PostOrderTree is now a subtype of the new IPA type). To fix this, Tom suggested the following (which is implemented in this PR): 1. Create a copy of the CFG tree classes (i.e., Pre/PostOrderTree, LeafTree, etc.) and call them AstPreOrderTree/AstPostOrderTree, AstLeafTree, etc. 2. For each tree AstTree from step 1, create a instance of the internal CFG library's appropriate class. 3. In `ControlFlowGraphImpl`, proceed as normal with virtual dispatch using `instanceof`, but extend the AstTree classes from step 1 instead of the CFG's own tree classes. This works because each AstTree implements one of the CFG library's tree classes (as per step 2). This commit performs step 1 and 2. Step 3 will be the next commit.
1 parent ab26851 commit 1f4924f

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
private import swift
2+
private import Completion
3+
private import ControlFlowGraphImplShared
4+
private import ControlFlowElements
5+
6+
abstract class AstControlFlowTree extends ControlFlowTree {
7+
AstNode ast;
8+
9+
AstControlFlowTree() { ast = this.asAstNode() }
10+
11+
AstNode getAst() { result = ast }
12+
}
13+
14+
/**
15+
* Holds if `first` is the first element executed within control flow
16+
* element `cft`.
17+
*/
18+
predicate astFirst(AstNode cft, ControlFlowElement first) {
19+
first(any(ControlFlowTree tree | cft = tree.asAstNode()), first)
20+
}
21+
22+
/**
23+
* Holds if `last` with completion `c` is a potential last element executed
24+
* within control flow element `cft`.
25+
*/
26+
predicate astLast(AstNode cft, ControlFlowElement last, Completion c) {
27+
last(any(ControlFlowTree tree | cft = tree.asAstNode()), last, c)
28+
}
29+
30+
abstract class AstPreOrderTree extends AstControlFlowTree, PreOrderTree { }
31+
32+
abstract class AstPostOrderTree extends AstControlFlowTree, PostOrderTree { }
33+
34+
abstract class AstStandardTree extends AstControlFlowTree, StandardTree { }
35+
36+
abstract class AstStandardPreOrderTree extends AstStandardTree, StandardPreOrderTree { }
37+
38+
abstract class AstStandardPostOrderTree extends AstStandardTree, StandardPostOrderTree { }
39+
40+
abstract class AstLeafTree extends AstPreOrderTree, AstPostOrderTree, LeafTree { }

0 commit comments

Comments
 (0)