diff --git a/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/MultiValueEvaluator.kt b/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/MultiValueEvaluator.kt index 56fb4c9348..0f6cd0e47d 100644 --- a/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/MultiValueEvaluator.kt +++ b/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/MultiValueEvaluator.kt @@ -32,8 +32,6 @@ import de.fraunhofer.aisec.cpg.graph.invoke import de.fraunhofer.aisec.cpg.graph.statements.DeclarationStatement import de.fraunhofer.aisec.cpg.graph.statements.ForStatement import de.fraunhofer.aisec.cpg.graph.statements.expressions.* -import de.fraunhofer.aisec.cpg.passes.EdgeCachePass -import de.fraunhofer.aisec.cpg.passes.astParent import org.slf4j.Logger import org.slf4j.LoggerFactory diff --git a/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/fsm/DFAOrderEvaluator.kt b/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/fsm/DFAOrderEvaluator.kt index a5467d553c..9d7f852835 100644 --- a/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/fsm/DFAOrderEvaluator.kt +++ b/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/fsm/DFAOrderEvaluator.kt @@ -35,7 +35,6 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression import de.fraunhofer.aisec.cpg.graph.statements.expressions.ConstructExpression import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberCallExpression import de.fraunhofer.aisec.cpg.graph.statements.expressions.Reference -import de.fraunhofer.aisec.cpg.passes.astParent import org.slf4j.Logger import org.slf4j.LoggerFactory diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Extensions.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Extensions.kt index 4200759a06..86bf2820f5 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Extensions.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Extensions.kt @@ -41,7 +41,6 @@ import de.fraunhofer.aisec.cpg.graph.statements.WhileStatement import de.fraunhofer.aisec.cpg.graph.statements.expressions.* import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker -import de.fraunhofer.aisec.cpg.passes.astParent import kotlin.math.absoluteValue /** diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt index d9eca8716d..7f412c00cc 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt @@ -158,6 +158,8 @@ open class Node : var astChildren: List = listOf() get() = SubgraphWalker.getAstChildren(this) + @Relationship("AST") var astParent: Node? = null + /** Virtual property for accessing [prevEOGEdges] without property edges. */ @PopulatedByPass(EvaluationOrderGraphPass::class) var prevEOG: List by PropertyEdgeDelegate(Node::prevEOGEdges, false) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt index cf7e12e01e..cdc7ee7af9 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt @@ -30,6 +30,7 @@ import de.fraunhofer.aisec.cpg.frontends.* import de.fraunhofer.aisec.cpg.graph.Node.Companion.EMPTY_NAME import de.fraunhofer.aisec.cpg.graph.NodeBuilder.LOGGER import de.fraunhofer.aisec.cpg.graph.NodeBuilder.log +import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration import de.fraunhofer.aisec.cpg.graph.scopes.Scope import de.fraunhofer.aisec.cpg.graph.statements.expressions.* import de.fraunhofer.aisec.cpg.graph.types.* @@ -39,6 +40,7 @@ import de.fraunhofer.aisec.cpg.passes.inference.IsInferredProvider import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation import de.fraunhofer.aisec.cpg.sarif.Region import java.net.URI +import kotlin.reflect.KProperty import org.slf4j.LoggerFactory object NodeBuilder { @@ -380,3 +382,51 @@ private fun Node.setCodeAndLocation( } this.location = provider.locationOf(rawNode) } + +context(ContextProvider) +fun T.withChildren( + hasScope: Boolean = false, + isGlobalScope: Boolean = false, + init: T.() -> Unit +): T { + val scopeManager = + this@ContextProvider.ctx?.scopeManager + ?: throw TranslationException( + "Trying to create node children without a ContextProvider. This will fail." + ) + + if (isGlobalScope && this is TranslationUnitDeclaration) { + scopeManager.resetToGlobal(this) + init(this) + } else if (hasScope) { + scopeManager.enterScope(this) + init(this) + scopeManager.leaveScope(this) + } else { + init(this) + } + + return this +} + +class AstProperty( + initializer: PropertyType, + var pre: ((PropertyType) -> Unit)? = null, + var post: ((PropertyType) -> Unit)? = null +) { + + private var storage: PropertyType = initializer + + operator fun getValue(thisRef: NodeType, property: KProperty<*>): PropertyType { + return storage + } + + operator fun setValue(thisRef: NodeType, property: KProperty<*>, value: PropertyType) { + pre?.let { it(storage) } + + storage = value + storage.astParent = thisRef + + post?.let { it(storage) } + } +} diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/BinaryOperator.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/BinaryOperator.kt index f37f34be63..c4c5c63132 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/BinaryOperator.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/BinaryOperator.kt @@ -41,22 +41,20 @@ import org.apache.commons.lang3.builder.ToStringBuilder open class BinaryOperator : Expression(), HasOverloadedOperation, ArgumentHolder, HasType.TypeObserver { /** The left-hand expression. */ - @AST - var lhs: Expression = ProblemExpression("could not parse lhs") - set(value) { - disconnectOldLhs() - field = value - connectNewLhs(value) - } + var lhs: Expression by + AstProperty( + initializer = ProblemExpression("could not parse lhs"), + pre = { disconnectOldLhs() }, + post = { connectNewLhs(it) } + ) /** The right-hand expression. */ - @AST - var rhs: Expression = ProblemExpression("could not parse rhs") - set(value) { - disconnectOldRhs() - field = value - connectNewRhs(value) - } + var rhs: Expression by + AstProperty( + initializer = ProblemExpression("could not parse rhs"), + pre = { disconnectOldRhs() }, + post = { connectNewRhs(it) } + ) /** The operator code. */ override var operatorCode: String? = null diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EdgeCachePass.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EdgeCachePass.kt index 3d97fca01d..0e0c29ef19 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EdgeCachePass.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EdgeCachePass.kt @@ -143,8 +143,3 @@ class EdgeCachePass(ctx: TranslationContext) : ComponentPass(ctx) { // nothing to do } } - -val Node.astParent: Node? - get() { - return Edges.to(this, EdgeType.AST).firstOrNull()?.source - } diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilderTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilderTest.kt index f5ce80f271..1dea80ee77 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilderTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilderTest.kt @@ -25,6 +25,7 @@ */ package de.fraunhofer.aisec.cpg.graph +import de.fraunhofer.aisec.cpg.frontends.TestLanguageFrontend import de.fraunhofer.aisec.cpg.graph.declarations.FieldDeclaration import de.fraunhofer.aisec.cpg.graph.edge.CallingContextIn import de.fraunhofer.aisec.cpg.graph.edge.ContextSensitiveDataflow @@ -34,6 +35,7 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.Literal import de.fraunhofer.aisec.cpg.graph.statements.expressions.Reference import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertNull import kotlin.test.assertTrue class ExpressionBuilderTest { @@ -70,4 +72,24 @@ class ExpressionBuilderTest { assertEquals(setOf(node1, clone), node2.prevDFG) } + + @Test + fun testBinaryOperatorParent() { + with(TestLanguageFrontend()) { + val lit1 = newLiteral(1) + assertNull(lit1.astParent) + + val lit2 = newLiteral(2) + assertNull(lit2.astParent) + + val binOp = + newBinaryOperator("+").withChildren { + lhs = lit1 + rhs = lit2 + } + + assertEquals(binOp, lit1.astParent) + assertEquals(binOp, lit2.astParent) + } + } }