diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt index d10dba13bf..dc75a7ea75 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt @@ -951,19 +951,54 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa private fun handleComprehensionExpression(node: ComprehensionExpression) { handleEOG(node.iterable) + // When the iterable contains another element, the variable is evaluated with the + // nextElement. Therefore we ad a + // true edge. + nextEdgeBranch = true handleEOG(node.variable) handleEOG(node.predicate) attachToEOG(node) + + // If the conditions evaluated to false, we need to retrieve the next element, therefore + // evaluating the iterable + drawEOGToEntriesOf(currentPredecessors, node.iterable, branchLabel = false) + + // If an element was found that fulfills the condition, we move forward + nextEdgeBranch = true } private fun handleCollectionComprehension(node: CollectionComprehension) { // Process the comprehension expressions from 0 to n and connect the EOG of i to i+1. - node.comprehensionExpressions.forEach { handleEOG(it) } - // TODO: Then, the EOG goes to the statement - handleEOG(node.statement) - // TODO: And jumps back to the first thing in the comprehension expressions + var prevComprehensionExpression: ComprehensionExpression? = null + var noMoreElementsEOGExits = listOf() + node.comprehensionExpressions.forEach { + handleEOG(it) + + // [ComprehensionExpression] yields no more elements => EOG:false + val prevComp = prevComprehensionExpression + if (prevComp == null) { + // We handle the EOG:false edges of the outermost comprehensionExpression later, + // they continue the + // path of execution when no more elements are yielded + noMoreElementsEOGExits = currentPredecessors.toList() + } else { + drawEOGToEntriesOf(currentPredecessors, prevComp.iterable, branchLabel = false) + } + prevComprehensionExpression = it - // Then goes to the whole node and we're done + // [ComprehensionExpression] yields and element => EOG:true + nextEdgeBranch = true + } + + handleEOG(node.statement) + // After evaluating the statement we + node.comprehensionExpressions.last().let { + drawEOGToEntriesOf(currentPredecessors, it.iterable) + } + currentPredecessors.clear() + currentPredecessors.addAll(noMoreElementsEOGExits) + nextEdgeBranch = + false // This path is followed when the comprehensions yield no more elements attachToEOG(node) } @@ -1242,4 +1277,13 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa else -> false } } + + fun drawEOGToEntriesOf(from: List, toEntriesOf: Node?, branchLabel: Boolean? = null) { + val tmpBranchLabel = nextEdgeBranch + branchLabel?.let { nextEdgeBranch = it } + SubgraphWalker.getEOGPathEdges(toEntriesOf).entries.forEach { entrance -> + addMultipleIncomingEOGEdges(from, entrance) + } + nextEdgeBranch = tmpBranchLabel + } } diff --git a/docs/docs/CPG/specs/eog.md b/docs/docs/CPG/specs/eog.md index f329474ab8..84f341767b 100644 --- a/docs/docs/CPG/specs/eog.md +++ b/docs/docs/CPG/specs/eog.md @@ -655,53 +655,6 @@ Interesting fields: Scheme: ```mermaid -flowchart LR - classDef outer fill:#fff,stroke:#ddd,stroke-dasharray:5 5; - prev:::outer --EOG--> child1["comprehensionExpressions[0]"] - child1 --EOG--> child2["comprehensionExpressions[n]"] - child2 --EOG--> child3["statement"] - child3 --EOG--> parent(["CollectionComprehension"]) - child3 --EOG--> child1 - parent --EOG--> next:::outer - parent -.-> child3 - parent -.-> child2 - parent -.-> child1 -``` - -Alternative: -```mermaid -flowchart LR - classDef outer fill:#fff,stroke:#ddd,stroke-dasharray:5 5; - prev:::outer --EOG--> child1["comprehensionExpressions[0]"] - child1 --EOG--> child2["comprehensionExpressions[n]"] - child2 --EOG--> parent(["CollectionComprehension"]) - - parent --EOG:true--> child3["statement"] - child3 --EOG--> child1 - parent --EOG:false--> next:::outer - parent -.-> child3 - parent -.-> child2 - parent -.-> child1 -``` -Alternative2: -```mermaid -flowchart LR - classDef outer fill:#fff,stroke:#ddd,stroke-dasharray:5 5; - prev:::outer --EOG--> child1["comprehensionExpressions[0]"] - child1 --EOG:true--> child2["comprehensionExpressions[n]"] - child1 --EOG:false--> next:::outer - child2 --EOG:true --> parent(["CollectionComprehension"]) - child2 --EOG:false--> next:::outer - - parent --EOG:true--> child3["statement"] - child3 --EOG--> child1 - parent --EOG:false--> next:::outer - parent -.-> child3 - parent -.-> child2 - parent -.-> child1 -``` -Alternative3: -```mermaid flowchart LR classDef outer fill:#fff,stroke:#ddd,stroke-dasharray:5 5; prev:::outer --EOG--> child1["comprehensionExpressions[0]"]