From 389eb0141b493c14f95d4db06d183e441b163e72 Mon Sep 17 00:00:00 2001 From: Konrad Weiss Date: Thu, 24 Oct 2024 12:54:36 +0200 Subject: [PATCH] Add test and fix EOG pass implementation --- .../aisec/cpg/graph/builder/Fluent.kt | 2 +- .../cpg/passes/EvaluationOrderGraphPass.kt | 10 +- .../de/fraunhofer/aisec/cpg/GraphExamples.kt | 34 +++++ .../passes/EvaluationOrderGraphPassTest.kt | 130 ++++++++++++++++++ 4 files changed, 171 insertions(+), 5 deletions(-) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/builder/Fluent.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/builder/Fluent.kt index 72995166c7..1f932d72f1 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/builder/Fluent.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/builder/Fluent.kt @@ -338,7 +338,7 @@ fun LanguageFrontend<*, *>.listComp( // Only add this to an argument holder if the nearest holder is an argument holder val holder = this@Holder - if (holder is ArgumentHolder) { + if (holder is StatementHolder) { holder += node } 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 dc75a7ea75..b7d29954ed 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 @@ -970,19 +970,21 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa private fun handleCollectionComprehension(node: CollectionComprehension) { // Process the comprehension expressions from 0 to n and connect the EOG of i to i+1. var prevComprehensionExpression: ComprehensionExpression? = null - var noMoreElementsEOGExits = listOf() + var noMoreElementsInCollection = listOf() node.comprehensionExpressions.forEach { handleEOG(it) + val noMoreElements = SubgraphWalker.getEOGPathEdges(it.iterable).exits + // [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() + noMoreElementsInCollection = noMoreElements } else { - drawEOGToEntriesOf(currentPredecessors, prevComp.iterable, branchLabel = false) + drawEOGToEntriesOf(noMoreElements, prevComp.iterable, branchLabel = false) } prevComprehensionExpression = it @@ -996,7 +998,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa drawEOGToEntriesOf(currentPredecessors, it.iterable) } currentPredecessors.clear() - currentPredecessors.addAll(noMoreElementsEOGExits) + currentPredecessors.addAll(noMoreElementsInCollection) nextEdgeBranch = false // This path is followed when the comprehensions yield no more elements attachToEOG(node) diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/GraphExamples.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/GraphExamples.kt index db0679a64d..4ccb5af4f0 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/GraphExamples.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/GraphExamples.kt @@ -243,6 +243,40 @@ class GraphExamples { } } + fun getNestedComprehensionExpressions( + config: TranslationConfiguration = + TranslationConfiguration.builder() + .defaultPasses() + .registerLanguage(TestLanguage(".")) + .build() + ) = + testFrontend(config).build { + translationResult { + translationUnit("whileWithBreakAndElse.py") { + record("someRecord") { + method("func") { + body { + call("preComprehensions") + listComp { + ref("i") + compExpr { + ref("i") + ref("someIterable") + } + compExpr { + ref("j") + ref("i") + ref("j") gt literal(5, t("int")) + } + } + call("postComprehensions") + } + } + } + } + } + } + fun testFrontend(config: TranslationConfiguration): TestLanguageFrontend { val ctx = TranslationContext(config, ScopeManager(), TypeManager()) val language = config.languages.filterIsInstance().first() diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPassTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPassTest.kt index ba200df7eb..ae6ff36a0a 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPassTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPassTest.kt @@ -27,6 +27,7 @@ package de.fraunhofer.aisec.cpg.passes import de.fraunhofer.aisec.cpg.GraphExamples import de.fraunhofer.aisec.cpg.graph.* +import de.fraunhofer.aisec.cpg.graph.statements.expressions.CollectionComprehension import de.fraunhofer.aisec.cpg.helpers.Util import kotlin.test.Test import kotlin.test.assertNotNull @@ -217,4 +218,133 @@ class EvaluationOrderGraphPassTest { cr = Util.Connect.SUBTREE ) } + + @Test + fun testCollectionComprehensionStatement() { + val compExample = GraphExamples.getNestedComprehensionExpressions() + + val listComp = compExample.allChildren().first() + assertNotNull(listComp) + + val preCall = compExample.calls["preComprehensions"] + assertNotNull(preCall) + + val postCall = compExample.calls["postComprehensions"] + assertNotNull(postCall) + + assertTrue { listComp.comprehensionExpressions.size == 2 } + + val outerComprehensionExpression = listComp.comprehensionExpressions.first() + assertNotNull(outerComprehensionExpression) + + val innerComprehensionExpression = listComp.comprehensionExpressions.last() + assertNotNull(innerComprehensionExpression) + + assertTrue( + Util.eogConnect( + en = Util.Edge.EXITS, + n = preCall, + refs = listOf(listComp), + cr = Util.Connect.SUBTREE + ) + ) + assertTrue( + Util.eogConnect( + en = Util.Edge.EXITS, + n = listComp, + refs = listOf(postCall), + cr = Util.Connect.SUBTREE + ) + ) + assertTrue( + Util.eogConnect( + en = Util.Edge.EXITS, + n = outerComprehensionExpression, + refs = + listOf( + innerComprehensionExpression, + listComp, + outerComprehensionExpression.variable + ), + cr = Util.Connect.SUBTREE + ) + ) + assertTrue( + Util.eogConnect( + q = Util.Quantifier.ANY, + en = Util.Edge.EXITS, + n = outerComprehensionExpression, + refs = + listOf( + innerComprehensionExpression, + ), + cr = Util.Connect.SUBTREE, + predicate = { it.branch == true } + ) + ) + + assertTrue( + Util.eogConnect( + q = Util.Quantifier.ANY, + en = Util.Edge.EXITS, + n = outerComprehensionExpression, + refs = listOf(listComp), + cr = Util.Connect.SUBTREE, + predicate = { it.branch == false } + ) + ) + + assertTrue( + Util.eogConnect( + en = Util.Edge.EXITS, + n = innerComprehensionExpression, + refs = listOf(outerComprehensionExpression, listComp.statement), + cr = Util.Connect.SUBTREE + ) + ) + + assertTrue( + Util.eogConnect( + q = Util.Quantifier.ANY, + en = Util.Edge.EXITS, + n = innerComprehensionExpression, + refs = listOf(listComp.statement), + cr = Util.Connect.SUBTREE, + predicate = { it.branch == true } + ) + ) + + assertTrue( + Util.eogConnect( + q = Util.Quantifier.ANY, + en = Util.Edge.EXITS, + n = innerComprehensionExpression, + refs = listOf(outerComprehensionExpression), + cr = Util.Connect.SUBTREE, + predicate = { it.branch == false } + ) + ) + + assertTrue( + Util.eogConnect( + q = Util.Quantifier.ANY, + en = Util.Edge.EXITS, + n = outerComprehensionExpression.iterable, + refs = listOf(outerComprehensionExpression.variable), + cr = Util.Connect.SUBTREE, + predicate = { it.branch == true } + ) + ) + + assertTrue( + Util.eogConnect( + q = Util.Quantifier.ANY, + en = Util.Edge.EXITS, + n = innerComprehensionExpression.iterable, + refs = listOf(innerComprehensionExpression.variable), + cr = Util.Connect.SUBTREE, + predicate = { it.branch == true } + ) + ) + } }