Skip to content

Commit c334f29

Browse files
committed
Added functions to insert a node in an existing EOG path
This adds two new extension functions `insertNodeBeforeInEOGPath` and `insertNodeAfterwardInEOGPath` that insert a new node into an existing EOG path either before or after the node of reference.
1 parent 7962b3c commit c334f29

File tree

2 files changed

+195
-10
lines changed

2 files changed

+195
-10
lines changed

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/EvaluationOrder.kt

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,89 @@ class EvaluationOrders<NodeType : Node>(
9191
outgoing = outgoing,
9292
),
9393
MirroredEdgeCollection<Node, EvaluationOrder>
94+
95+
/**
96+
* This function inserts the given [newNode] before the current node ([this]) in its existing EOG
97+
* path.
98+
*
99+
* Before:
100+
* ```
101+
* <node1> -- EOG -->
102+
* <node3>
103+
* <node2> -- EOG -->
104+
* ```
105+
*
106+
* We want to insert a new [EvaluationOrder] edge between all incoming edges of [this] (node3).
107+
*
108+
* Afterward:
109+
* ```
110+
* <node1> -- EOG -->
111+
* <new node> -- EOG --> <node3>
112+
* <node2> -- EOG -->
113+
* ```
114+
*/
115+
fun Node.insertNodeBeforeInEOGPath(
116+
newNode: Node,
117+
builder: ((EvaluationOrder) -> Unit)? = null,
118+
): Boolean {
119+
// Construct a new edge from the given node to the current node
120+
val edge = EvaluationOrder(newNode, this).also(builder ?: {})
121+
122+
// Make a copy of the incoming edges of the current node and set the start of the new edge as
123+
// the end
124+
val copy = this.prevEOGEdges.toList()
125+
copy.forEach { it.end = edge.start }
126+
127+
// Clear the incoming edges of the current node
128+
this.prevEOGEdges.clear()
129+
130+
// Add the old edges as the previous edges of the new edge's start. We cannot use "addAll"
131+
// because otherwise our mirroring will not be triggered.
132+
copy.forEach { edge.start.prevEOGEdges += it }
133+
134+
// Add the new edge as a previous edge of the current node
135+
return this.prevEOGEdges.add(edge)
136+
}
137+
138+
/**
139+
* This function inserts the given [newNode] after the current node ([this]) in its existing EOG
140+
* path.
141+
*
142+
* Before:
143+
* ```
144+
* -- EOG --> <node1>
145+
* <node3>
146+
* -- EOG --> <node2>
147+
* ```
148+
*
149+
* We want to insert a new [EvaluationOrder] edge between all outgoing edges of [this] (node3).
150+
*
151+
* Afterward:
152+
* ```
153+
* -- EOG --> <node1>
154+
* <node3> -- EOG --> <new node>
155+
* -- EOG --> <node2>
156+
* ```
157+
*/
158+
fun Node.insertNodeAfterwardInEOGPath(
159+
newNode: Node,
160+
builder: ((EvaluationOrder) -> Unit)? = null,
161+
): Boolean {
162+
// Construct a new edge from the current node to the given node
163+
val edge = EvaluationOrder(this, newNode).also(builder ?: {})
164+
165+
// Make a copy of the outgoing edges of the current node and set the end of the new edge as
166+
// the start
167+
val copy = this.nextEOGEdges.toList()
168+
copy.forEach { it.start = edge.end }
169+
170+
// Clear the outgoing edges of the current node
171+
this.nextEOGEdges.clear()
172+
173+
// Add the old edges as the next edges of the new edge's end. We cannot use "addAll" because
174+
// otherwise our mirroring will not be triggered.
175+
copy.forEach { edge.end.nextEOGEdges += it }
176+
177+
// Add the new edge as a next edge of the current node
178+
return this.nextEOGEdges.add(edge)
179+
}

cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/EvaluationOrderTest.kt

Lines changed: 109 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,18 @@ class EvaluationOrderTest {
3434
fun testEvaluationOrders() {
3535
with(TestLanguageFrontend()) {
3636
// <node1> -- EOG --> <node2>
37-
// this should be 1 nextDFG for node1 and 1 prevDFG for node2
38-
var node1 = newLiteral(value = 1)
39-
var node2 = newLiteral(value = 1)
40-
37+
// this should be 1 nextEOG for node1 and 1 prevEOG for node2
38+
val node1 = newLiteral(value = 1)
39+
val node2 = newLiteral(value = 2)
4140
node1.nextEOGEdges.add(node2)
42-
// should contain 1 prevDFG edge now
41+
42+
// should contain 1 prevEOG edge now
4343
assertEquals(1, node2.prevEOGEdges.size)
44-
// and it should be the same as the nextDFG of node1
44+
// and it should be the same as the nextEOG of node1
4545
assertSame(node1.nextEOGEdges.firstOrNull(), node2.prevEOGEdges.firstOrNull())
4646

4747
node1.nextEOGEdges.removeAt(0)
48-
// should contain 0 prevDFG edge now
48+
// should contain 0 prevEOG edge now
4949
assertEquals(0, node2.prevEOGEdges.size)
5050
}
5151
}
@@ -54,9 +54,9 @@ class EvaluationOrderTest {
5454
fun testClear() {
5555
with(TestLanguageFrontend()) {
5656
// <node1> -- EOG --> <node2>
57-
// this should be 1 nextDFG for node1 and 1 prevDFG for node2
58-
var node1 = newLiteral(value = 1)
59-
var node2 = newLiteral(value = 1)
57+
// this should be 1 nextEOG for node1 and 1 prevEOG for node2
58+
val node1 = newLiteral(value = 1)
59+
val node2 = newLiteral(value = 2)
6060

6161
node1.nextEOGEdges.add(node2)
6262
assertEquals(1, node2.prevEOGEdges.size)
@@ -66,4 +66,103 @@ class EvaluationOrderTest {
6666
assertEquals(0, node2.prevEOGEdges.size)
6767
}
6868
}
69+
70+
@Test
71+
fun testInsertBefore() {
72+
with(TestLanguageFrontend()) {
73+
val node1 = newLiteral(value = 1)
74+
val node2 = newLiteral(value = 2)
75+
val node3 = newLiteral(value = 3)
76+
77+
// <node1> -- EOG -->
78+
// <node3>
79+
// <node2> -- EOG -->
80+
node1.nextEOGEdges += node3
81+
node2.nextEOGEdges += node3
82+
assertEquals(2, node3.prevEOGEdges.size, "node3 should contain 2 prevEOG edges now")
83+
assertEquals(
84+
setOf(node1, node2),
85+
node3.prevEOG.toSet(),
86+
"node3 should have node1 and node2 as prevEOG",
87+
)
88+
89+
// Now let's insert an edge from node4 to node3 "before" node3
90+
// <node1> -- EOG -->
91+
// <node4> -- EOG --> <node3>
92+
// <node2> -- EOG -->
93+
val node4 = newLiteral(value = 4)
94+
assertTrue(node3.insertNodeBeforeInEOGPath(node4))
95+
assertEquals(1, node3.prevEOGEdges.size, "node3 should contain 1 prevEOG edge now")
96+
assertSame(
97+
node4,
98+
node3.prevEOGEdges.singleOrNull()?.start,
99+
"node4 should be the start of the single prevEOG edge of node3",
100+
)
101+
assertEquals(2, node4.prevEOGEdges.size, "node4 should contain 2 prevEOG edges now")
102+
assertEquals(
103+
setOf(node1, node2),
104+
node4.prevEOG.toSet(),
105+
"node4 should have node1 and node2 as prevEOG",
106+
)
107+
assertEquals(1, node1.nextEOGEdges.size, "node1 should contain 1 nextEOG edge now")
108+
assertSame(
109+
node4,
110+
node1.nextEOGEdges.singleOrNull()?.end,
111+
"node4 should be the end of the single nextEOG edge of node1",
112+
)
113+
}
114+
}
115+
116+
@Test
117+
fun testInsertAfterward() {
118+
with(TestLanguageFrontend()) {
119+
val node1 = newLiteral(value = 1)
120+
val node2 = newLiteral(value = 2)
121+
val node3 = newLiteral(value = 3)
122+
123+
// -- EOG --> <node1>
124+
// <node3>
125+
// -- EOG --> <node2>
126+
//
127+
node3.nextEOGEdges += node1
128+
node3.nextEOGEdges += node2
129+
assertEquals(2, node3.nextEOGEdges.size, "node3 should contain 2 nextEOG edges now")
130+
assertEquals(
131+
setOf(node1, node2),
132+
node3.nextEOG.toSet(),
133+
"node3 should have node1 and node2 as nextEOG",
134+
)
135+
136+
// Now let's insert an edge from node3 to node4 "after" node3
137+
// -- EOG --> <node1>
138+
// <node3> -- EOG --> <node4>
139+
// -- EOG --> <node2>
140+
val node4 = newLiteral(value = 4)
141+
assertTrue(node3.insertNodeAfterwardInEOGPath(node4))
142+
assertEquals(1, node3.nextEOGEdges.size, "node3 should contain 1 nextEOG edge now")
143+
assertSame(
144+
node4,
145+
node3.nextEOGEdges.singleOrNull()?.end,
146+
"node4 should be the end of the single nextEOG edge of node3",
147+
)
148+
assertEquals(2, node4.nextEOGEdges.size, "node4 should contain 2 nextEOG edges now")
149+
assertEquals(
150+
setOf(node1, node2),
151+
node4.nextEOG.toSet(),
152+
"node4 should have node1 and node2 as nextEOG",
153+
)
154+
assertEquals(1, node1.prevEOGEdges.size, "node1 should contain 1 prevEOG edge now")
155+
assertSame(
156+
node4,
157+
node1.prevEOGEdges.singleOrNull()?.start,
158+
"node4 should be the start of the single prevEOG edge of node1",
159+
)
160+
assertEquals(1, node2.prevEOGEdges.size, "node2 should contain 1 prevEOG edge now")
161+
assertSame(
162+
node4,
163+
node2.prevEOGEdges.singleOrNull()?.start,
164+
"node4 should be the start of the single prevEOG edge of node2",
165+
)
166+
}
167+
}
69168
}

0 commit comments

Comments
 (0)