From e6d198081960df59f1ddbf33aa5705da93e8f89d Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Wed, 11 Dec 2024 14:51:01 +0100 Subject: [PATCH] Pseudo-support for multi-labels --- .../de/fraunhofer/aisec/cpg/graph/Assignment.kt | 2 +- .../fraunhofer/aisec/cpg/graph/MermaidPrinter.kt | 2 +- .../de/fraunhofer/aisec/cpg/graph/edges/Edge.kt | 2 +- .../aisec/cpg/graph/edges/ast/AstEdge.kt | 16 ++++++++-------- .../cpg/graph/edges/ast/TemplateArgument.kt | 2 +- .../cpg/graph/edges/flows/ControlDependence.kt | 2 +- .../aisec/cpg/graph/edges/flows/Dataflow.kt | 4 ++-- .../cpg/graph/edges/flows/EvaluationOrder.kt | 2 +- .../aisec/cpg/graph/edges/flows/Invoke.kt | 2 +- .../aisec/cpg/graph/edges/flows/Usage.kt | 2 +- .../statements/expressions/CallExpression.kt | 2 +- .../de/fraunhofer/aisec/cpg/v2/Persistence.kt | 16 ++++++++++------ 12 files changed, 29 insertions(+), 25 deletions(-) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Assignment.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Assignment.kt index 6cc946d0d1..d20a0c82e5 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Assignment.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Assignment.kt @@ -46,5 +46,5 @@ class Assignment( /** The holder of this assignment */ @JsonIgnore val holder: AssignmentHolder ) : Edge(value, target as Node) { - override var label: String = "ASSIGMENT" + override var labels = setOf("ASSIGMENT") } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/MermaidPrinter.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/MermaidPrinter.kt index 6f04d5dd1b..1da2d709ce 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/MermaidPrinter.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/MermaidPrinter.kt @@ -109,7 +109,7 @@ fun > Node.printGraph( private fun Edge.label(): String { val builder = StringBuilder() builder.append("\"") - builder.append(this.label) + builder.append(this.labels) if (this is Dataflow) { var granularity = this.granularity diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/Edge.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/Edge.kt index 8b3d5dea42..064b0caa29 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/Edge.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/Edge.kt @@ -71,7 +71,7 @@ abstract class Edge : Persistable, Cloneable { end = edge.end } - abstract var label: String + abstract var labels: Set /** * The index of this node, if it is stored in an diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/ast/AstEdge.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/ast/AstEdge.kt index a83d7ed01d..5e7d09dce9 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/ast/AstEdge.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/ast/AstEdge.kt @@ -33,7 +33,7 @@ import org.neo4j.ogm.annotation.* /** This property edge describes a parent/child relationship in the Abstract Syntax Tree (AST). */ @RelationshipEntity -open class AstEdge(start: Node, end: T, override var label: String = "AST") : +open class AstEdge(start: Node, end: T, override var labels: Set = setOf("AST")) : Edge(start, end) { init { end.astParent = start @@ -42,7 +42,7 @@ open class AstEdge(start: Node, end: T, override var label: String = " /** Creates an [AstEdges] container starting from this node. */ fun Node.astEdgesOf( - label: String = "AST", + label: String? = null, onAdd: ((AstEdge) -> Unit)? = null, onRemove: ((AstEdge) -> Unit)? = null, ): AstEdges> { @@ -54,12 +54,12 @@ fun Node.astEdgesOf( * container). */ fun Node.astOptionalEdgeOf( - label: String = "AST", + label: String? = null, onChanged: ((old: AstEdge?, new: AstEdge?) -> Unit)? = null ): EdgeSingletonList> { return EdgeSingletonList( thisRef = this, - init = { start, end -> AstEdge(start, end, label = label) }, + init = { start, end -> AstEdge(start, end, labels = setOfNotNull(label, "AST")) }, outgoing = true, onChanged = onChanged, of = null @@ -71,12 +71,12 @@ fun Node.astOptionalEdgeOf( */ fun Node.astEdgeOf( of: NodeType, - label: String, + label: String? = null, onChanged: ((old: AstEdge?, new: AstEdge?) -> Unit)? = null, ): EdgeSingletonList> { return EdgeSingletonList( thisRef = this, - init = { start, end -> AstEdge(start, end, label = label) }, + init = { start, end -> AstEdge(start, end, labels = setOfNotNull(label, "AST")) }, outgoing = true, onChanged = onChanged, of = of @@ -86,12 +86,12 @@ fun Node.astEdgeOf( /** This property edge list describes elements that are AST children of a node. */ open class AstEdges>( thisRef: Node, - label: String = "AST", + label: String? = null, onAdd: ((PropertyEdgeType) -> Unit)? = null, onRemove: ((PropertyEdgeType) -> Unit)? = null, @Suppress("UNCHECKED_CAST") init: (start: Node, end: NodeType) -> PropertyEdgeType = { start, end -> - AstEdge(start, end, label = label) as PropertyEdgeType + AstEdge(start, end, labels = setOfNotNull(label, "AST")) as PropertyEdgeType }, ) : EdgeList( diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/ast/TemplateArgument.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/ast/TemplateArgument.kt index b06c3bdfd1..46374d959c 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/ast/TemplateArgument.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/ast/TemplateArgument.kt @@ -35,7 +35,7 @@ class TemplateArgument( end: NodeType, label: String, var instantiation: TemplateInitialization? = TemplateInitialization.EXPLICIT, -) : AstEdge(start, end, label) +) : AstEdge(start, end, setOf(label, "AST")) /** A container for [TemplateArgument] edges. */ class TemplateArguments(thisRef: Node, label: String) : diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/ControlDependence.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/ControlDependence.kt index 3591e0eaf5..5f3badedad 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/ControlDependence.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/ControlDependence.kt @@ -49,7 +49,7 @@ class ControlDependence( dependence = DependenceType.CONTROL } - override var label: String = "CDG" + override var labels = setOf("CDG") override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Dataflow.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Dataflow.kt index 4ce9ff4ebd..07ba1dc104 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Dataflow.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Dataflow.kt @@ -93,7 +93,7 @@ open class Dataflow( @JsonIgnore var granularity: Granularity = default() ) : Edge(start, end) { - override var label: String = "DFG" + override var labels = setOf("DFG") override fun equals(other: Any?): Boolean { if (this === other) return true @@ -134,7 +134,7 @@ class ContextSensitiveDataflow( val callingContext: CallingContext ) : Dataflow(start, end, granularity) { - override var label: String = "DFG" + override var labels = setOf("DFG") override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/EvaluationOrder.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/EvaluationOrder.kt index e6af5e8d81..7ac7126b3b 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/EvaluationOrder.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/EvaluationOrder.kt @@ -69,7 +69,7 @@ class EvaluationOrder( return result } - override var label: String = "EOG" + override var labels = setOf("EOG") } /** diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Invoke.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Invoke.kt index e6a9499683..9bbaffad82 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Invoke.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Invoke.kt @@ -43,7 +43,7 @@ class Invoke( */ var dynamicInvoke: Boolean = false, ) : Edge(start, end) { - override var label: String = "INVOKES" + override var labels = setOf("INVOKES") override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Usage.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Usage.kt index b4a41a6821..0178456adf 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Usage.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edges/flows/Usage.kt @@ -53,7 +53,7 @@ class Usage( return result } - override var label: String = "USAGE" + override var labels = setOf("USAGE") } /** A container for [Usage] edges. [NodeType] is necessary because of the Neo4J OGM. */ diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/CallExpression.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/CallExpression.kt index 218ae9d250..e33affe188 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/CallExpression.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/CallExpression.kt @@ -121,7 +121,7 @@ open class CallExpression : /** Adds the specified [expression] with an optional [name] to this call. */ fun addArgument(expression: Expression, name: String? = null) { - val edge = AstEdge(this, expression, label = "ARGUMENTS") + val edge = AstEdge(this, expression, labels = setOf("ARGUMENTS", "ARGUMENT")) edge.name = name argumentEdges.add(edge) diff --git a/cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg/v2/Persistence.kt b/cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg/v2/Persistence.kt index 8e7d4f9cb9..d5b01e3d03 100644 --- a/cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg/v2/Persistence.kt +++ b/cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg/v2/Persistence.kt @@ -138,12 +138,16 @@ private fun Collection>.persist() { this.chunked(edgeChunkSize).map { chunk -> createRelationships( - chunk.map { - mapOf( - "startId" to it.start.id.toString(), - "endId" to it.end.id.toString(), - "type" to it.label - ) + it.properties() + chunk.flatMap { edge -> + // Since Neo4J does not support multiple labels on edges, but we do internally, we + // duplicate the edge for each label + edge.labels.map { label -> + mapOf( + "startId" to edge.start.id.toString(), + "endId" to edge.end.id.toString(), + "type" to label + ) + edge.properties() + } } ) }